Setting up the environment

# Packages
library(ggplot2)
library(dplyr)
library(plotly)
library(tidyr)
library(RColorBrewer)
library(limma)
library(gplots)
library(edgeR)
library(devtools)
library(ggbiplot)
library(DESeq)
library(geneplotter)
library(Rtsne)
set.seed(1234) # makes everything reproductible 
meta_data <- read.table("../Data/raw_data/meta_data.txt", header = TRUE)
dataInitial <- read.table("../Data/raw_data/expn_matrix.txt", header = TRUE, row.names = 1)
spike_data <- read.table("../Data/raw_data/expn_matrix_spike.txt", header = TRUE, row.names = 1)

Normalization

Kevin’s normalization

Here the data is normalized based on the spike_data we have. Although this seems to be correct, there could be some issues: See post.

spike_data <- rbind(spike_data, "Totals" = colSums(spike_data)) #finding sum of column and adding it as new row
scaled_totals <- spike_data["Totals", ]
average_reads <- rowMeans(scaled_totals)
scaled_totals <- rbind(scaled_totals, "Scale" = scaled_totals[1, ] / average_reads) #dividing total spike values by average spike values
dim_names <- list(row.names(dataInitial))       #setting dim_names for upcoming matrix
dim_names[2] <- list(colnames((dataInitial)))
normalized_data <- matrix(nrow = nrow(dataInitial), ncol = ncol(dataInitial), dimnames = dim_names) #pre-making a matrix
for(i in 1: ncol(dataInitial)){   #for loop which scales data and saves it as normalized_data
  normalized_data[ , i] <- dataInitial[ , i] / scaled_totals[2, i]
}
normalized_data <- as.data.frame(normalized_data)
#normalizing for cell size (cellular miRNA counts)
total_data <- rbind(spike_data, "Total Spike" = colSums(spike_data), "Total Reads" = colSums(dataInitial))
total_cellular <- total_data["Total Reads", ]
average_reads <- rowMeans(total_cellular)
cell_scales <- rbind(total_cellular, "Scale" = total_cellular[1, ] / average_reads) #dividing total spike values by average spike values
dim_names <- list(row.names(dataInitial))       #setting dim_names for upcoming matrix
dim_names[2] <- list(colnames((dataInitial)))
normalized_data2 <- matrix(nrow = nrow(dataInitial), ncol = ncol(dataInitial), dimnames = dim_names) #pre-making a matrix
for(i in 1: ncol(dataInitial)){   #for loop which scales data and saves it as normalized_data
  normalized_data2[ , i] <- normalized_data[ , i] / scaled_totals[2, i]
}
normalized_data2 <- as.data.frame(normalized_data2)
# deleting dead cells
alive_indexes <- list() #initializing lists
k <- 1  #initializing counter
for(i in 1:ncol(total_data)){
  if(total_data["Total Reads", i] > 20000){
    alive_indexes[k] <- i
    k <- k + 1
  }
}
alive_data <- normalized_data2[ , as.numeric(alive_indexes)]
alive_meta_data <- meta_data[as.numeric(alive_indexes), ]
#Saving completely normalized data as n_data and n_meta_data
n_data <- alive_data
n_meta_data <- alive_meta_data
#makes group and design matrix
data_day <- as.character(n_meta_data$Population)
data_day <- recode(data_day, "HL60D0" = "Day 0", "HL60D1" = "Day 1", "HL60D3" = "Day 3", "HL60D7" = "Day 7")
data_day <-factor(data_day)
design <- model.matrix(~0 + n_meta_data$Population)
#deletes "n_meta_data$Population" from name of columns
colnames(design) <- gsub("n_meta_data\\$Population", "", colnames(design))
#lets call intercept HL60D0
#colnames(design)[1] <- "HL60D0"
# Keeps genes without all zeros miRNA
dataNZ <- n_data[which(rowSums(n_data) > 0),] 
#making the contrast matrix
# let's suppose for now that we want to compare each group with each other ?????????????????????????
contrastMatrix <- makeContrasts(HL60D1-HL60D0,
                                HL60D3-HL60D0,
                                HL60D7-HL60D0,
                                HL60D1-HL60D3,
                                HL60D1-HL60D7,
                                HL60D3-HL60D7,
                                levels = c("HL60D0","HL60D1","HL60D3","HL60D7"))
#will not be needed: don't keep big data
remove(normalized_data)
remove(normalized_data2)
remove(alive_data)

Please note that with this normalization, we are only using cells ????????????????(alive cells?)

General normalization

To be sure that the normalization is good I will continue the analysis with a more general normalization. The following is based on this page. By general I mean not specific to pikes.

data_dayDESeq <- as.character(meta_data$Population)
data_dayDESeq <- recode(data_dayDESeq, "HL60D0" = "Day 0", "HL60D1" = "Day 1", "HL60D3" = "Day 3", "HL60D7" = "Day 7")
data_dayDESeq <-factor(data_dayDESeq)
deSeqDat <- newCountDataSet(dataInitial, data_dayDESeq)
# Note: actually it's not a real normalisation. Rather computing size factors depending on ratio of medians 
# if all size factors are roughly equal to one, the libraries have been sequenced equally deeply.
deSeqDat <- estimateSizeFactors(deSeqDat)
head(sizeFactors(deSeqDat))
HL60D0.C01_S1 HL60D0.C02_S2 HL60D0.C03_S3 HL60D0.C04_S4 HL60D0.C05_S5 HL60D0.C06_S6 
    0.5254052     1.1318130     0.9646220     0.3233751     1.3896389     0.9596427 
idx.nz <- apply(counts(deSeqDat), 1, function(x) { all(x > 0)})
nNZsamples <- sum(idx.nz)
#will not be needed: don't keep big data
remove(dataInitial)

We see that the number of non zero samples in all genes is very low compared to traditional RNA-seq: 5 nomrally in thousands. This may be a good reason to stick with the normalization with skie RNA.

#plotting the estimated dispersions against the mean normalized counts
deSeqDat <- estimateDispersions(deSeqDat)
plotDispEsts(deSeqDat)

multidensity( counts(deSeqDat, normalized = T),xlab="mean counts", xlim=c(0, 1000))

 multiecdf( counts(deSeqDat, normalized = T),xlab="mean counts", xlim=c(0, 1000))

The two charts above clearly shows that the second normalisation isn’t convincing. Indeed, the second chart assesses whether the normalization has worked, and the densities should overlapp since most of the genes are heavily affected by the experimental conditions. Note: The strange density chart could also be due to the fact that miRNA are very rarely expressed in every sample (as we have seen before).

Plots

PCA

PCA no standardization

First we use a log transformation to make the data approximatively follow the homoscedasticity assumption.

#Log transform
log_normalized_data <- log(dataNZ)
log_normalized_data[log_normalized_data == "-Inf"] <- 0
data_pca <- prcomp(t(log_normalized_data))
g <- ggbiplot(data_pca, 
              scale = 1, 
              obs.scale = 1, 
              varname.abbrev = FALSE,
              var.axes = FALSE,
              pc.biplot =TRUE,
              circle = TRUE, 
              groups = data_day, 
              ellipse= TRUE) +
  ggtitle("PCA without standardizing") +
  theme(text = element_text(size=14),plot.title = element_text(hjust = 0.5)) 
g 

#will not be needed: don't keep big data
#remove(g)
remove(data_pca)
remove(log_normalized_data)

Note: The PCA graph is interesting as it shows that after each day the clusters seem to go down in PC2 and extend their variance in PC1.

PCA standardized

Knowing the importance of having standardized data for PCA, we could think of standarding ours. This in general is a good idea, as veraibles are often not on the same scale and thus cannot be compared directly. Here, on revanche we have dimensions that are comparable as they each represent the number of miRNA in each cell. It is therefore a good idea not to standrdize, as it will unnecessarily decrease the variance explained. More information on this can be found on the following forums: (here)[http://stats.stackexchange.com/questions/105592/not-normalizing-data-before-pca-gives-better-explained-variance-ratio] or (here)[http://stats.stackexchange.com/questions/69157/why-do-we-need-to-normalize-data-before-analysis]. Out of curiosity we will still plot the standardized data:

#Log transform
log_normalized_dataNZ <- log(dataNZ)
log_normalized_dataNZ[log_normalized_dataNZ == "-Inf"] <- 0
data_pcaNZ <- prcomp(t(log_normalized_dataNZ), center = TRUE, scale. = TRUE)
g <- ggbiplot(data_pcaNZ, 
              scale = 1, 
              obs.scale = 1, 
              varname.abbrev = FALSE,
              var.axes = FALSE,
              pc.biplot =TRUE,
              circle = TRUE, 
              groups = data_day, 
              ellipse= TRUE) +
  ggtitle("PCA non zero genes") +
  theme(text = element_text(size=14),plot.title = element_text(hjust = 0.5)) 
g 

#will not be needed: don't keep big data
#remove(g)
remove(data_pcaNZ)
remove(log_normalized_dataNZ)

From this plot we see that as we’ve supposed, the variance explained is lower than in the first one. We thus conclude that we should stick with the first plot as we can (because on the same scale).

PCA top 50

Let’s now plot the top 50 genes

#arranging data based on total expression
indexTopFifty <- sort(rowSums(n_data), index=T, decreasing=TRUE)$ix[1:50]
topFifty <- n_data[indexTopFifty,]
# note: small difference with kenny probably come from the fact that he did log before and then took top fifty 
#Log transform
log_topFifty <- log(topFifty)
log_topFifty[log_topFifty == "-Inf"] <- 0
#PCA
data_topFifty <- prcomp(t(log_topFifty))
g <- ggbiplot(data_topFifty, 
              scale = 1, 
              obs.scale = 1, 
              varname.abbrev = FALSE,
              var.axes = FALSE,
              pc.biplot =TRUE,
              circle = TRUE, 
              groups = data_day, 
              ellipse= TRUE) +
  ggtitle("PCA top 50 genes") +
  theme(text = element_text(size=14),plot.title = element_text(hjust = 0.5)) 
g

#will not be needed: don't keep big data
#remove(g)
remove(data_topFifty)
remove(log_topFifty)
remove(topFifty)

Correlation heatmap

# Note: both plots of dataNZ and full data gives same correlation heatmap
normalized_data_cor <- cor(dataNZ)  #calculating sample-sample correlations
scaled_normalized_data_cor <- scale(normalized_data_cor)  #scaling for better contrast
limit <- 2
scaled_normalized_data_cor[which(scaled_normalized_data_cor > limit)] <- limit    #trimming for better contrast
scaled_normalized_data_cor[which(scaled_normalized_data_cor < -limit)] <- -limit
mypal <- rev(colorRampPalette(brewer.pal(11,"RdBu"))(100)) #setting colour palette
alphabet <- c("#b2df8a","#33a02c","#ff7f00","#fdbf6f","#b15928","#1f78b4","#6a3d9a","#e31a1c","#a6cee3","#cab2d6","#ffff99","#fb9a99")
pops <- alphabet[as.factor(data_day)] #setting population colour palette
heatmap.2(scaled_normalized_data_cor, Rowv = NA, Colv = NA, symm = T, #making a heatmap
          trace = "none", dendrogram = "none", col = mypal,
          labCol = NA, labRow = NA,
          cexCol = 0.45, cexRow = 0.45, main = "Sample-Sample Correlations",
          ColSideColors = pops) 

#will not be needed: don't keep big data
remove(normalized_data_cor)
remove(scaled_normalized_data_cor)
#remove(heatmapPlot)

In this heat map we clearly see the high correlation between the samples of day 0 and 1 and between the samples of day 3 and 7.

t-SNE plots

General t-SNE

Let’s plot the t-SNE plots of the cells that aren’t dead to see if we can find clusters and / or outliers. Note that we aren’t taking into account genes that aren’t expressed in any samples.

# t-SNE plot with alive cells and non zero genes
#ordering data by expn
alive_tsne_data <- cbind(dataNZ, "avg_expn" = rowMeans(dataNZ), "miRNA" = row.names(dataNZ)) 
alive_tsne_data <- dplyr::arrange(alive_tsne_data,desc(avg_expn))
alive_tsne_data <- t(alive_tsne_data)
colnames(alive_tsne_data) <- alive_tsne_data["miRNA", ]
#removes rows that were added for ordering
alive_tsne_data <- alive_tsne_data[!rownames(alive_tsne_data) %in% c("miRNA","avg_expn"), ]
tsne_out <- Rtsne(dist(alive_tsne_data)) # Run TSNE
# Show the objects in the 2D tsne representation
tSNETotal <- qplot(x=tsne_out$Y[,1], y=tsne_out$Y[,2],color=data_day) + 
  labs(colour = "Cell Type", x = "tsne1", y = "tsne2")+
  ggtitle("t-SNE alive cells and non zero genes") +
  theme(text = element_text(size=14),plot.title = element_text(hjust = 0.5)) 
tSNETotal

#will not be needed: don't keep big data
remove(tsne_out)
#remove(tSNETotal)

As with the correlation heatmap, we see that the samples from day 0 and 1 are clustered together while those from day 3 and 7 are clustered together.

t-SNE of Day 0 and Day 1

Now that we have seen that the samples from day 0 and 1 are closely related. Let’s try to take only those 2 in order to see if we can separate them from each other.

#tsne on Day 0/Day 1 cells only
indexDay01 <- which(data_day %in% c("Day 0","Day 1"))
group_one_data <- alive_tsne_data[indexDay01, ] #selecting only day 0 and day 1 cells
tsne_out <- Rtsne(dist(group_one_data)) # Run TSNE
# Show the objects in the 2D tsne representation
tsneDay01 <- qplot(x=tsne_out$Y[,1], y=tsne_out$Y[,2],color=data_day[indexDay01]) +
  labs(colour = "Cell Type", x = "tsne1", y = "tsne2") +
  ggtitle("t-SNE only day 0 and 1") +
  theme(text = element_text(size=14),plot.title = element_text(hjust = 0.5)) 
tsneDay01

#will not be needed: don't keep big data
remove(tsne_out)
#remove(tsneDay01)

The t-SNE can clearly not separate the 2 samples from each other. Finally let’s investigate whether they can be separated with a t-SNE in 3 dimension:

tsne_out <- Rtsne(dist(group_one_data), dims = 3) # Run TSNE in 3 dimensions
plot_ly(x=tsne_out$Y[,1],
        y=tsne_out$Y[,2],
        z=tsne_out$Y[,3],
        type="scatter3d",
        color=data_day[indexDay01],
        mode="markers") %>% 
  layout(title = 't-SNE day 0 and 1 3D')

#will not be needed: don't keep big data
remove(tsne_out)
remove(group_one_data)
#remove(tsneDay01)

We can still not distinguish both type of cells. This really shows how similar they are.

t-SNE of Day 0 and Day 1

Now let’s look at the cluster Day 3 and 7, to see if they can be distinguished.

#tsne on Day 0/Day 1 cells only
indexDay37 <- which(data_day %in% c("Day 3","Day 7"))
group_two_data <- alive_tsne_data[indexDay37, ] #selecting only day 0 and day 1 cells
tsne_out <- Rtsne(dist(group_two_data)) # Run TSNE
# Show the objects in the 2D tsne representation
tsneDay37 <- qplot(x=tsne_out$Y[,1], y=tsne_out$Y[,2],color=data_day[indexDay37]) +
  labs(colour = "Cell Type", x = "tsne1", y = "tsne2") +
  ggtitle("t-SNE only day 3 and 7") +
  theme(text = element_text(size=14),plot.title = element_text(hjust = 0.5)) 
tsneDay37

#will not be needed: don't keep big data
remove(tsne_out)
remove(alive_tsne_data)
#remove(tsneDay37)

As before, the 2 type of cells cannot be distinguished with a t-SNE plot in 2D. They will probably not be distinguishable in 3D but let’s be sure:

tsne_out <- Rtsne(dist(group_two_data), dims = 3) # Run TSNE in 3 dimensions
plot_ly(x=tsne_out$Y[,1],
        y=tsne_out$Y[,2],
        z=tsne_out$Y[,3],
        type="scatter3d",
        color=data_day[indexDay37],
        mode="markers") %>% 
  layout(title = 't-SNE day 3 and 7 3D')

#will not be needed: don't keep big data
remove(tsne_out)
remove(group_two_data)

Not suprisingly, the second cluster cannot be seprated further with 3 dimensional t-SNE.

Fit linear model

Note that for fitting linear models, we cannot use the DATASEQ library as it requires counts (i.e. discrete values). We now have continuous values because of they way we normalized the data.

Voom

Mean-Variance trend

Initial Mean-Variance tren

First let us visualize the mean-variance trend, to see.

#working ... HOW TO USE DATADESEQ ON NORMALIZED => NOT COUNTS ANY MORE?? + IS IT WORTH IT ? cAN we round ?
#dataDESeq <- rlog(as.matrix(data), blind=FALSE )
dge <- DGEList(counts=dataNZ, group = data_day)
# applies TMM normalization to dge
dge <- calcNormFactors(dge)
data_voomed <- voom(dge,design,plot=TRUE)

#will not be needed: don't keep big data
remove(dge)

The mean-variance trend is suprising: it doesn’t look flat enough. The first hyporthesis we had is that we there was a problem because we normalize by samples and then limma does it again. But not normailizing our data doesn’t change the curve of the plot. We then thought that maybe limma was doing something that required discrete data (as it is made for count data), our data isn’t discrete as we normailized it based on spike RNA. But rounding the data doesn’t change anything either. We will have to look deeper at the meaning of te curve of the plot and whether our data doesn’t follow the Voom assumptions. Note that the data may also be strange due to the nature of miRNA data, indeed in RNAseq we often have high value of counts but in miRNA the number of counts are much lower. This could cause the spike we see below x = zero (i.e. very low mean).

Lets check whether the strange mean variance is due to the clusters that we had.

df <- data_voomed$E
dataf<- mutate(data.frame(t(df)), group = data_day) %>% 
  gather(mirna, exp, - group) 
ggplot(dataf, aes(x=exp)) + 
  geom_histogram(aes(color = group)) +
  ggtitle("Initial istogram of counts") +
  theme(text = element_text(size=14),plot.title = element_text(hjust = 0.5)) 

We see that our model seems to be bimodal but that the bimodality doesn’t seem to be due to the clusters.

Final Mean-Variance

We realized that is important that we use only the genes with no non zero values for every sample as we can see in paragraph 15.3 of (limma manual)[https://www.bioconductor.org/packages/devel/bioc/vignettes/limma/inst/doc/usersguide.pdf]. From the same article they say that as a rule of thumb is to retain rows that have at least 10 counts for a worthwhile number of samples.

dataNZFilterd <-dataNZ[rowSums(dataNZ>=10)>=round(0.3*ncol(dataNZ)),]
dge <- DGEList(counts=dataNZFilterd, group = data_day)
# applies TMM normalization to dge
#dge <- dge[isExpr,]
dge <- calcNormFactors(dge)
data_voomed <- voom(dge,design,plot=TRUE)

#will not be needed: don't keep big data
remove(dge)

It is now already a bit better. We also see that the mean variance trend seam to be decreasing very quickly and steadily, we can thus conclude that the experiment seem to be of low biological variation. For more information please see the “Removing heteroscedascity from count data” subpart of (this paper)[https://f1000research.com/articles/5-1408]

Here is an example of the data we have:

data_voomed[1:2,1:10]
An object of class "EList"
$targets
               group  lib.size norm.factors
HL60D0.C01_S1  Day 0  98643.51    0.9722808
HL60D0.C02_S2  Day 0  71913.77    0.9919387
HL60D0.C03_S3  Day 0  60085.97    1.0149911
HL60D0.C04_S4  Day 0 269051.46    0.9274848
HL60D0.C05_S5  Day 0  61654.79    1.0837952
HL60D0.C06_S6  Day 0  43943.05    1.0092054
HL60D0.C07_S7  Day 0 132684.23    0.9131704
HL60D0.C08_S8  Day 0  59127.47    1.1386215
HL60D0.C09_S10 Day 0 218444.65    1.0948769
HL60D0.C10_S11 Day 0  57710.01    1.2096569

$E
              HL60D0.C01_S1 HL60D0.C02_S2 HL60D0.C03_S3 HL60D0.C04_S4 HL60D0.C05_S5
hsa-let-7a-5p     13.406560     12.814684      12.92698     7.7084698      13.15058
hsa-let-7a-3p      2.341617      2.797568      10.12266     0.8940406      10.22792
              HL60D0.C06_S6 HL60D0.C07_S7 HL60D0.C08_S8 HL60D0.C09_S10 HL60D0.C10_S11
hsa-let-7a-5p      13.23362      13.04953     13.541487      12.720075      13.252301
hsa-let-7a-3p      10.25054       1.91392      9.819029       9.354078       9.812598

$weights
          [,1]      [,2]      [,3]      [,4]      [,5]      [,6]      [,7]      [,8]
[1,] 0.9303631 0.7013970 0.6018274 2.6953635 0.6149923 0.4656913 1.2368403 0.5937921
[2,] 0.1360968 0.1201292 0.1128750 0.2259304 0.1137440 0.1032960 0.1560068 0.1123739
          [,9]     [,10]
[1,] 2.1068200 0.5819193
[2,] 0.2012992 0.1116230

$design
   HL60D0 HL60D1 HL60D3 HL60D7
1       1      0      0      0
2       1      0      0      0
3       1      0      0      0
4       1      0      0      0
5       1      0      0      0
6       1      0      0      0
7       1      0      0      0
8       1      0      0      0
9       1      0      0      0
10      1      0      0      0

Final mean-variance bis

Thinking about it, we shouldn’t filter on having as good percentage of the samples that are non zero but rather having a majority of non zero in at least one group we have. Indeed that’s what really interests us at the end, because we are going to compare the groups!

indexDay0 <- which(data_day == "Day 0")
indexDay1 <- which(data_day == "Day 1")
indexDay3 <- which(data_day == "Day 3")
indexDay7 <- which(data_day == "Day 7")
dataNZFilterdBis <- dataNZ[rowSums(dataNZ[,indexDay0]>=10)>=round(0.50*length(indexDay0)) |
                          rowSums(dataNZ[,indexDay1]>=10)>=round(0.50*length(indexDay1)) |
                          rowSums(dataNZ[,indexDay3]>=10)>=round(0.50*length(indexDay3)) |
                          rowSums(dataNZ[,indexDay7]>=10)>=round(0.50*length(indexDay7)) ,]
dge <- DGEList(counts=dataNZFilterdBis, group = data_day)
# applies TMM normalization to dge
#dge <- dge[isExpr,]
dge <- calcNormFactors(dge)
data_voomed <- voom(dge,design,plot=TRUE)

#will not be needed: don't keep big data
remove(dge)

We see that it is very close to before but at least now there’s no subjectivity of “a worthile number of samples need to have more than 10 counts for that miRNA”.

Lets look now at the histogram to see how it changed it:

df <- data_voomed$E
dataf<- mutate(data.frame(t(df)), group = data_day) %>% 
  gather(mirna, exp, - group) 
ggplot(dataf, aes(x=exp)) + 
  geom_histogram(aes(color = group)) +
  ggtitle("Final histogram of counts") +
  theme(text = element_text(size=14),plot.title = element_text(hjust = 0.5)) 

Why strange shape?: I just realized the reason of the strange shape: everything is due to the extreme variance at low count ! Indeed generally the mean variance plot shows a \(\sqrt(SD)\) that is around 1, but ours is around 2, but only at a low count. The reason is simple: the clusters! We can now explain all the curve: in the unfiltered mean-variance plot there was a strange ascent at the bigining, this is due to the fact that miRNA have a relatively low number of counts and is either on or off so we had a lot of zeros, these are now filtered out. Then there is a very big variance at low to average number of counts, this is due to the fact that the clusters are very strong in our samples, the miRNA are either on or off depending on the clusters (cluster 1: day 0 and 1, cluster 2: day 3 and 7) so when looking at possibly interesting miRNA they are often on in one of the cluster and off in the other this thus results in a relatively low number of counts but a very big variance (bimodal data). Fow high counts we see that the variance is really low, this is simply showing “not interesting” miRNA that are always very high and thus have a low variance!

One good way to go around that is to look differently at the genes that are always high and those that are only high in one of the clusters (when they are low in both they were already filtered out). Lets look at the plots to see if this hypothesis is true

Always high mirRNA
rowsAlwaysHigh <- rowSums(dataNZFilterdBis>=12.5)>=round(0.80*ncol(dataNZFilterdBis))
dataNZFilterAlwaysHigh <- dataNZFilterdBis[rowsAlwaysHigh,]
dge <- DGEList(counts=dataNZFilterAlwaysHigh, group = data_day)
# applies TMM normalization to dge
#dge <- dge[isExpr,]
dge <- calcNormFactors(dge)
data_voomedAH <- voom(dge,design,plot=TRUE)

#will not be needed: don't keep big data
remove(dge)

If the hypothesis is true then the histogram should be now normally distributed (no more binomial because the genes we are looking at are always highly expressed)

df <- data_voomedAH$E
dataf<- mutate(data.frame(t(df)), group = data_day) %>% 
  gather(mirna, exp, - group) 
ggplot(dataf, aes(x=exp)) + 
  geom_histogram(aes(color = group)) +
  ggtitle("Initial istogram of counts") +
  theme(text = element_text(size=14),plot.title = element_text(hjust = 0.5)) 

miRNA high in a single group
dataNZFilterHighSingleGroup <- dataNZFilterdBis[!rowsAlwaysHigh,]
dge <- DGEList(counts=dataNZFilterHighSingleGroup, group = data_day)
# applies TMM normalization to dge
#dge <- dge[isExpr,]
dge <- calcNormFactors(dge)
data_voomedHSG <- voom(dge,design,plot=TRUE)

#will not be needed: don't keep big data
remove(dge)

Now here there should still be a bimodal distribution as when one cluster is high the other one will be low and vis versa.

df <- data_voomedHSG$E
dataf<- mutate(data.frame(t(df)), group = data_day) %>% 
  gather(mirna, exp, - group) 
ggplot(dataf, aes(x=exp)) + 
  geom_histogram(aes(color = group)) +
  ggtitle("Initial istogram of counts") +
  theme(text = element_text(size=14),plot.title = element_text(hjust = 0.5)) 

we see that as hypthosized the histogramm is bimodal

Mean variance trend no log

NOTE: this is not important any more ! Note: Seeing the strange plot above makes us think that maybe our count data doesn’t need to be log transformed. Let’s investigate the relationship between the mean and the variance of ou data.

#working ... HOW TO USE DATADESEQ ON NORMALIZED => NOT COUNTS ANY MORE?? + IS IT WORTH IT ? cAN we round ?
#dataDESeq <- rlog(as.matrix(data), blind=FALSE )
#takes only genes that are non zero in many samples
#t <- n_data[which(rowSums(n_data) > 300),] 
#tries plotting directly without voom
m <- rowMeans(dataNZ)
RowSigmaSqrt <- function(x) {
  (rowSums((x - rowMeans(x))^2)/(dim(x)[2] - 1))^(1/4)
}
v <- RowSigmaSqrt(dataNZ)
plotxy <- data.frame(mean=m,sigmaSqrt=v)
ggplot(plotxy, aes(x=mean, y=sigmaSqrt)) +
    geom_point(shape=1) +    # Use hollow circles
    geom_smooth(method=lm,   # Add linear regression line
                se=FALSE) + # Don't add shaded confidence region
  ylim(0, 7500) + 
  xlim(0,7500) + 
  ggtitle("Mean variance relationship not Voom") +
  theme(text = element_text(size=14),plot.title = element_text(hjust = 0.5)) 

From this plot we clearly see that our variance grows with fourth poqer of our mean. The reasoning behind this different relationship is still unclear to us (????????????? biologically), but it could indicate that we shouldn’t work with the default limma package and that we should maybe do the analysis manually (????????).

Fit linear model

fit <- lmFit(data_voomed, design)
fit <- contrasts.fit(fit, contrasts=contrastMatrix)
efit <- eBayes(fit)
topTable(efit, coef=colnames(coef(efit)))
plotSA(efit)

#will not be needed: don't keep big data
remove(fit)
remove(data_voomed)

Here there is a problem as we do not see the fitted line (?????).

Examining the number of DE genes

Let’s now look at differential expression levels of genes. Note that the adjusted p-value cutoff is 5%.

dt <- decideTests(efit)
summary(dt)
   HL60D1 - HL60D0 HL60D3 - HL60D0 HL60D7 - HL60D0 HL60D1 - HL60D3 HL60D1 - HL60D7
-1              20              13              70              58              33
0               96              76              30              59              29
1               10              37              26               9              64
   HL60D3 - HL60D7
-1              27
0               15
1               84

As we have already previously seen in the multiple plots of the previous section: most differential expressed genes are between day 0/1 and 3/7. We also note that a lot of genes in Day 3 and 7 are downregulated (compared to day 0 and 1).

Finding genes that are often differentially expressed compared to day 0

Let’s look at the genes that are always differentially expressed compared to day 0

# Finding genes that are not zero in every comparaison with day 0
commonDEgenesDay0 <- which(dt[,1]!=0 & dt[,2]!=0 & dt[,3]!=0)
names(commonDEgenesDay0)
 [1] "hsa-let-7a-3p"   "hsa-miR-132-3p"  "hsa-miR-143-3p"  "hsa-miR-17-3p"  
 [5] "hsa-miR-181b-5p" "hsa-miR-181b-3p" "hsa-miR-199b-5p" "hsa-miR-19b-3p" 
 [9] "hsa-miR-221-3p"  "hsa-miR-223-3p"  "hsa-miR-28-3p"   "hsa-miR-30d-5p" 
[13] "hsa-miR-30e-5p"  "hsa-miR-378a-3p" "hsa-miR-99b-5p" 

Let’s visualise it with a nice venn diagramm

vennDiagram(dt[,1:3], circle.col=c("turquoise", "salmon", "green"))

Finding genes that are often differentially between day 0/1 and day 3/7

Let’s look at the genes that are always differentially between day 0/1 and 3/7 as they seem to be the ones of interest.

# Finding genes that are not zero in every comparaison with day 0
commonDEgenesDay0137 <- which(dt[,2]!=0 & dt[,3]!=0 & dt[,4]!=0 & dt[,5]!=0)
names(commonDEgenesDay0137)
 [1] "hsa-let-7d-3p"   "hsa-let-7i-5p"   "hsa-miR-125a-5p" "hsa-miR-132-3p" 
 [5] "hsa-miR-143-3p"  "hsa-miR-145-5p"  "hsa-miR-181b-3p" "hsa-miR-185-5p" 
 [9] "hsa-miR-192-5p"  "hsa-miR-19b-3p"  "hsa-miR-223-3p"  "hsa-miR-23a-3p" 
[13] "hsa-miR-26a-5p"  "hsa-miR-30e-5p"  "hsa-miR-425-5p"  "hsa-miR-425-3p" 
[17] "hsa-miR-92a-3p" 

Let’s visualise it with a nice venn diagramm

vennDiagram(dt[,2:5], circle.col=c("turquoise", "salmon", "green","yellow"))

Finding genes that are differentially expressed between clusters but not whithin clusters

Finally what we are really interested in are genes that are differentially expressed between clusters but not whithin clusters: here are these genes:

# Finding genes that are differentially expressed between clusters but not whithin clusters
commonDEgenesBetweenNotWhithin <- which(dt[,2]!=0 & dt[,3]!=0 & dt[,4]!=0 & dt[,5]!=0 & dt[,1]==0 & dt[,6]==0)
names(commonDEgenesBetweenNotWhithin)
[1] "hsa-let-7d-3p"  "hsa-miR-192-5p" "hsa-miR-92a-3p"
LS0tCnRpdGxlOiAiU3VtbWFyeSB3b3JrIgphdXRob3I6ICJLZXZpbiBKZXBzb24sIFN0ZXBoYW5pZSBCbGFpbiwgTWFja2VuemllIEtpbm5leSwgR2FycmV0dCBNY0NhcnRoeSwgS2VubmV0aCBBc2tlbHNvbiBhbmQgWWFubiBEdWJvaXMiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKaGVhZGVyLWluY2x1ZGVzOiBcdXNlcGFja2FnZXthbXNtYXRofQotLS0KCiMgU2V0dGluZyB1cCB0aGUgZW52aXJvbm1lbnQKCmBgYHtyIGxvYWRpbmdfZGF0YSwgcmVzdWx0cz0naGlkZScsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgUGFja2FnZXMKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeSh0aWR5cikKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkobGltbWEpCmxpYnJhcnkoZ3Bsb3RzKQpsaWJyYXJ5KGVkZ2VSKQpsaWJyYXJ5KGRldnRvb2xzKQpsaWJyYXJ5KGdnYmlwbG90KQpsaWJyYXJ5KERFU2VxKQpsaWJyYXJ5KGdlbmVwbG90dGVyKQpsaWJyYXJ5KFJ0c25lKQoKc2V0LnNlZWQoMTIzNCkgIyBtYWtlcyBldmVyeXRoaW5nIHJlcHJvZHVjdGlibGUgCgptZXRhX2RhdGEgPC0gcmVhZC50YWJsZSgiLi4vRGF0YS9yYXdfZGF0YS9tZXRhX2RhdGEudHh0IiwgaGVhZGVyID0gVFJVRSkKZGF0YUluaXRpYWwgPC0gcmVhZC50YWJsZSgiLi4vRGF0YS9yYXdfZGF0YS9leHBuX21hdHJpeC50eHQiLCBoZWFkZXIgPSBUUlVFLCByb3cubmFtZXMgPSAxKQpzcGlrZV9kYXRhIDwtIHJlYWQudGFibGUoIi4uL0RhdGEvcmF3X2RhdGEvZXhwbl9tYXRyaXhfc3Bpa2UudHh0IiwgaGVhZGVyID0gVFJVRSwgcm93Lm5hbWVzID0gMSkKYGBgCgojTm9ybWFsaXphdGlvbiAKCiMjS2V2aW4ncyBub3JtYWxpemF0aW9uCgpIZXJlIHRoZSBkYXRhIGlzIG5vcm1hbGl6ZWQgYmFzZWQgb24gdGhlIHNwaWtlX2RhdGEgd2UgaGF2ZS4gQWx0aG91Z2ggdGhpcyBzZWVtcyB0byBiZSBjb3JyZWN0LCB0aGVyZSBjb3VsZCBiZSBzb21lIGlzc3VlczogW1NlZSBwb3N0XShodHRwczovL3N1cHBvcnQuYmlvY29uZHVjdG9yLm9yZy9wLzc0ODcwLykuCgpgYGB7ciBub3JtYWxpemVfa2V2aW59CnNwaWtlX2RhdGEgPC0gcmJpbmQoc3Bpa2VfZGF0YSwgIlRvdGFscyIgPSBjb2xTdW1zKHNwaWtlX2RhdGEpKSAjZmluZGluZyBzdW0gb2YgY29sdW1uIGFuZCBhZGRpbmcgaXQgYXMgbmV3IHJvdwpzY2FsZWRfdG90YWxzIDwtIHNwaWtlX2RhdGFbIlRvdGFscyIsIF0KYXZlcmFnZV9yZWFkcyA8LSByb3dNZWFucyhzY2FsZWRfdG90YWxzKQpzY2FsZWRfdG90YWxzIDwtIHJiaW5kKHNjYWxlZF90b3RhbHMsICJTY2FsZSIgPSBzY2FsZWRfdG90YWxzWzEsIF0gLyBhdmVyYWdlX3JlYWRzKSAjZGl2aWRpbmcgdG90YWwgc3Bpa2UgdmFsdWVzIGJ5IGF2ZXJhZ2Ugc3Bpa2UgdmFsdWVzCgpkaW1fbmFtZXMgPC0gbGlzdChyb3cubmFtZXMoZGF0YUluaXRpYWwpKSAgICAgICAjc2V0dGluZyBkaW1fbmFtZXMgZm9yIHVwY29taW5nIG1hdHJpeApkaW1fbmFtZXNbMl0gPC0gbGlzdChjb2xuYW1lcygoZGF0YUluaXRpYWwpKSkKCm5vcm1hbGl6ZWRfZGF0YSA8LSBtYXRyaXgobnJvdyA9IG5yb3coZGF0YUluaXRpYWwpLCBuY29sID0gbmNvbChkYXRhSW5pdGlhbCksIGRpbW5hbWVzID0gZGltX25hbWVzKSAjcHJlLW1ha2luZyBhIG1hdHJpeAoKZm9yKGkgaW4gMTogbmNvbChkYXRhSW5pdGlhbCkpeyAgICNmb3IgbG9vcCB3aGljaCBzY2FsZXMgZGF0YSBhbmQgc2F2ZXMgaXQgYXMgbm9ybWFsaXplZF9kYXRhCiAgbm9ybWFsaXplZF9kYXRhWyAsIGldIDwtIGRhdGFJbml0aWFsWyAsIGldIC8gc2NhbGVkX3RvdGFsc1syLCBpXQp9Cm5vcm1hbGl6ZWRfZGF0YSA8LSBhcy5kYXRhLmZyYW1lKG5vcm1hbGl6ZWRfZGF0YSkKCiNub3JtYWxpemluZyBmb3IgY2VsbCBzaXplIChjZWxsdWxhciBtaVJOQSBjb3VudHMpCnRvdGFsX2RhdGEgPC0gcmJpbmQoc3Bpa2VfZGF0YSwgIlRvdGFsIFNwaWtlIiA9IGNvbFN1bXMoc3Bpa2VfZGF0YSksICJUb3RhbCBSZWFkcyIgPSBjb2xTdW1zKGRhdGFJbml0aWFsKSkKdG90YWxfY2VsbHVsYXIgPC0gdG90YWxfZGF0YVsiVG90YWwgUmVhZHMiLCBdCmF2ZXJhZ2VfcmVhZHMgPC0gcm93TWVhbnModG90YWxfY2VsbHVsYXIpCmNlbGxfc2NhbGVzIDwtIHJiaW5kKHRvdGFsX2NlbGx1bGFyLCAiU2NhbGUiID0gdG90YWxfY2VsbHVsYXJbMSwgXSAvIGF2ZXJhZ2VfcmVhZHMpICNkaXZpZGluZyB0b3RhbCBzcGlrZSB2YWx1ZXMgYnkgYXZlcmFnZSBzcGlrZSB2YWx1ZXMKCmRpbV9uYW1lcyA8LSBsaXN0KHJvdy5uYW1lcyhkYXRhSW5pdGlhbCkpICAgICAgICNzZXR0aW5nIGRpbV9uYW1lcyBmb3IgdXBjb21pbmcgbWF0cml4CmRpbV9uYW1lc1syXSA8LSBsaXN0KGNvbG5hbWVzKChkYXRhSW5pdGlhbCkpKQoKbm9ybWFsaXplZF9kYXRhMiA8LSBtYXRyaXgobnJvdyA9IG5yb3coZGF0YUluaXRpYWwpLCBuY29sID0gbmNvbChkYXRhSW5pdGlhbCksIGRpbW5hbWVzID0gZGltX25hbWVzKSAjcHJlLW1ha2luZyBhIG1hdHJpeAoKZm9yKGkgaW4gMTogbmNvbChkYXRhSW5pdGlhbCkpeyAgICNmb3IgbG9vcCB3aGljaCBzY2FsZXMgZGF0YSBhbmQgc2F2ZXMgaXQgYXMgbm9ybWFsaXplZF9kYXRhCiAgbm9ybWFsaXplZF9kYXRhMlsgLCBpXSA8LSBub3JtYWxpemVkX2RhdGFbICwgaV0gLyBzY2FsZWRfdG90YWxzWzIsIGldCn0Kbm9ybWFsaXplZF9kYXRhMiA8LSBhcy5kYXRhLmZyYW1lKG5vcm1hbGl6ZWRfZGF0YTIpCgojIGRlbGV0aW5nIGRlYWQgY2VsbHMKCmFsaXZlX2luZGV4ZXMgPC0gbGlzdCgpICNpbml0aWFsaXppbmcgbGlzdHMKayA8LSAxICAjaW5pdGlhbGl6aW5nIGNvdW50ZXIKZm9yKGkgaW4gMTpuY29sKHRvdGFsX2RhdGEpKXsKICBpZih0b3RhbF9kYXRhWyJUb3RhbCBSZWFkcyIsIGldID4gMjAwMDApewogICAgYWxpdmVfaW5kZXhlc1trXSA8LSBpCiAgICBrIDwtIGsgKyAxCiAgfQp9CgphbGl2ZV9kYXRhIDwtIG5vcm1hbGl6ZWRfZGF0YTJbICwgYXMubnVtZXJpYyhhbGl2ZV9pbmRleGVzKV0KYWxpdmVfbWV0YV9kYXRhIDwtIG1ldGFfZGF0YVthcy5udW1lcmljKGFsaXZlX2luZGV4ZXMpLCBdCgojU2F2aW5nIGNvbXBsZXRlbHkgbm9ybWFsaXplZCBkYXRhIGFzIG5fZGF0YSBhbmQgbl9tZXRhX2RhdGEKbl9kYXRhIDwtIGFsaXZlX2RhdGEKbl9tZXRhX2RhdGEgPC0gYWxpdmVfbWV0YV9kYXRhCgojbWFrZXMgZ3JvdXAgYW5kIGRlc2lnbiBtYXRyaXgKZGF0YV9kYXkgPC0gYXMuY2hhcmFjdGVyKG5fbWV0YV9kYXRhJFBvcHVsYXRpb24pCmRhdGFfZGF5IDwtIHJlY29kZShkYXRhX2RheSwgIkhMNjBEMCIgPSAiRGF5IDAiLCAiSEw2MEQxIiA9ICJEYXkgMSIsICJITDYwRDMiID0gIkRheSAzIiwgIkhMNjBENyIgPSAiRGF5IDciKQpkYXRhX2RheSA8LWZhY3RvcihkYXRhX2RheSkKCmRlc2lnbiA8LSBtb2RlbC5tYXRyaXgofjAgKyBuX21ldGFfZGF0YSRQb3B1bGF0aW9uKQojZGVsZXRlcyAibl9tZXRhX2RhdGEkUG9wdWxhdGlvbiIgZnJvbSBuYW1lIG9mIGNvbHVtbnMKY29sbmFtZXMoZGVzaWduKSA8LSBnc3ViKCJuX21ldGFfZGF0YVxcJFBvcHVsYXRpb24iLCAiIiwgY29sbmFtZXMoZGVzaWduKSkKI2xldHMgY2FsbCBpbnRlcmNlcHQgSEw2MEQwCiNjb2xuYW1lcyhkZXNpZ24pWzFdIDwtICJITDYwRDAiCgojIEtlZXBzIGdlbmVzIHdpdGhvdXQgYWxsIHplcm9zIG1pUk5BCmRhdGFOWiA8LSBuX2RhdGFbd2hpY2gocm93U3VtcyhuX2RhdGEpID4gMCksXSAKCiNtYWtpbmcgdGhlIGNvbnRyYXN0IG1hdHJpeAojIGxldCdzIHN1cHBvc2UgZm9yIG5vdyB0aGF0IHdlIHdhbnQgdG8gY29tcGFyZSBlYWNoIGdyb3VwIHdpdGggZWFjaCBvdGhlciA/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/CmNvbnRyYXN0TWF0cml4IDwtIG1ha2VDb250cmFzdHMoSEw2MEQxLUhMNjBEMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBITDYwRDMtSEw2MEQwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEhMNjBENy1ITDYwRDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSEw2MEQxLUhMNjBEMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBITDYwRDEtSEw2MEQ3LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEhMNjBEMy1ITDYwRDcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiSEw2MEQwIiwiSEw2MEQxIiwiSEw2MEQzIiwiSEw2MEQ3IikpCgojd2lsbCBub3QgYmUgbmVlZGVkOiBkb24ndCBrZWVwIGJpZyBkYXRhCnJlbW92ZShub3JtYWxpemVkX2RhdGEpCnJlbW92ZShub3JtYWxpemVkX2RhdGEyKQpyZW1vdmUoYWxpdmVfZGF0YSkKYGBgCgpQbGVhc2Ugbm90ZSB0aGF0IHdpdGggdGhpcyBub3JtYWxpemF0aW9uLCB3ZSBhcmUgb25seSB1c2luZyBjZWxscyA/Pz8/Pz8/Pz8/Pz8/Pz8/KGFsaXZlIGNlbGxzPykKCiMjR2VuZXJhbCBub3JtYWxpemF0aW9uIAoKVG8gYmUgc3VyZSB0aGF0IHRoZSBub3JtYWxpemF0aW9uIGlzIGdvb2QgSSB3aWxsIGNvbnRpbnVlIHRoZSBhbmFseXNpcyB3aXRoIGEgbW9yZSBnZW5lcmFsIG5vcm1hbGl6YXRpb24uIFRoZSBmb2xsb3dpbmcgaXMgYmFzZWQgb24gW3RoaXMgcGFnZV0oaHR0cDovL3d3dy1odWJlci5lbWJsLmRlL3VzZXJzL2tsYXVzL1RlYWNoaW5nL0RFU2VxMlByZWRvYzIwMTQuaHRtbCNwY2EtYW5kLXNhbXBsZS1oZWF0bWFwcykuIEJ5IGdlbmVyYWwgSSBtZWFuIG5vdCBzcGVjaWZpYyB0byBwaWtlcy4KCmBgYHtyIG5vcm1hbGl6ZV9ERVNlcX0KZGF0YV9kYXlERVNlcSA8LSBhcy5jaGFyYWN0ZXIobWV0YV9kYXRhJFBvcHVsYXRpb24pCmRhdGFfZGF5REVTZXEgPC0gcmVjb2RlKGRhdGFfZGF5REVTZXEsICJITDYwRDAiID0gIkRheSAwIiwgIkhMNjBEMSIgPSAiRGF5IDEiLCAiSEw2MEQzIiA9ICJEYXkgMyIsICJITDYwRDciID0gIkRheSA3IikKZGF0YV9kYXlERVNlcSA8LWZhY3RvcihkYXRhX2RheURFU2VxKQoKZGVTZXFEYXQgPC0gbmV3Q291bnREYXRhU2V0KGRhdGFJbml0aWFsLCBkYXRhX2RheURFU2VxKQoKIyBOb3RlOiBhY3R1YWxseSBpdCdzIG5vdCBhIHJlYWwgbm9ybWFsaXNhdGlvbi4gUmF0aGVyIGNvbXB1dGluZyBzaXplIGZhY3RvcnMgZGVwZW5kaW5nIG9uIHJhdGlvIG9mIG1lZGlhbnMgCiMgaWYgYWxsIHNpemUgZmFjdG9ycyBhcmUgcm91Z2hseSBlcXVhbCB0byBvbmUsIHRoZSBsaWJyYXJpZXMgaGF2ZSBiZWVuIHNlcXVlbmNlZCBlcXVhbGx5IGRlZXBseS4KCmRlU2VxRGF0IDwtIGVzdGltYXRlU2l6ZUZhY3RvcnMoZGVTZXFEYXQpCmhlYWQoc2l6ZUZhY3RvcnMoZGVTZXFEYXQpKQoKaWR4Lm56IDwtIGFwcGx5KGNvdW50cyhkZVNlcURhdCksIDEsIGZ1bmN0aW9uKHgpIHsgYWxsKHggPiAwKX0pCm5OWnNhbXBsZXMgPC0gc3VtKGlkeC5ueikKCiN3aWxsIG5vdCBiZSBuZWVkZWQ6IGRvbid0IGtlZXAgYmlnIGRhdGEKcmVtb3ZlKGRhdGFJbml0aWFsKQpgYGAKCldlIHNlZSB0aGF0IHRoZSBudW1iZXIgb2Ygbm9uIHplcm8gc2FtcGxlcyBpbiBhbGwgZ2VuZXMgaXMgdmVyeSBsb3cgY29tcGFyZWQgdG8gdHJhZGl0aW9uYWwgUk5BLXNlcTogYHIgbk5ac2FtcGxlc2Agbm9tcmFsbHkgaW4gdGhvdXNhbmRzLiBUaGlzIG1heSBiZSBhIGdvb2QgcmVhc29uIHRvIHN0aWNrIHdpdGggdGhlIG5vcm1hbGl6YXRpb24gd2l0aCBza2llIFJOQS4KCmBgYHtyIHBsb3R0X2Rpc3BlcnNpb259CiNwbG90dGluZyB0aGUgZXN0aW1hdGVkIGRpc3BlcnNpb25zIGFnYWluc3QgdGhlIG1lYW4gbm9ybWFsaXplZCBjb3VudHMKZGVTZXFEYXQgPC0gZXN0aW1hdGVEaXNwZXJzaW9ucyhkZVNlcURhdCkKcGxvdERpc3BFc3RzKGRlU2VxRGF0KQptdWx0aWRlbnNpdHkoIGNvdW50cyhkZVNlcURhdCwgbm9ybWFsaXplZCA9IFQpLHhsYWI9Im1lYW4gY291bnRzIiwgeGxpbT1jKDAsIDEwMDApKQpgYGAKCmBgYHtyIHBsb3R0X2RlbnNpdHl9CiBtdWx0aWVjZGYoIGNvdW50cyhkZVNlcURhdCwgbm9ybWFsaXplZCA9IFQpLHhsYWI9Im1lYW4gY291bnRzIiwgeGxpbT1jKDAsIDEwMDApKQpgYGAKClRoZSB0d28gY2hhcnRzIGFib3ZlIGNsZWFybHkgc2hvd3MgdGhhdCB0aGUgc2Vjb25kIG5vcm1hbGlzYXRpb24gaXNuJ3QgY29udmluY2luZy4gSW5kZWVkLCB0aGUgc2Vjb25kIGNoYXJ0IGFzc2Vzc2VzIHdoZXRoZXIgdGhlIG5vcm1hbGl6YXRpb24gaGFzIHdvcmtlZCwgYW5kIHRoZSBkZW5zaXRpZXMgc2hvdWxkIG92ZXJsYXBwIHNpbmNlIG1vc3Qgb2YgdGhlIGdlbmVzIGFyZSBoZWF2aWx5IGFmZmVjdGVkIGJ5IHRoZSBleHBlcmltZW50YWwgY29uZGl0aW9ucy4gTm90ZTogVGhlIHN0cmFuZ2UgZGVuc2l0eSBjaGFydCBjb3VsZCBhbHNvIGJlIGR1ZSB0byB0aGUgZmFjdCB0aGF0IG1pUk5BIGFyZSB2ZXJ5IHJhcmVseSBleHByZXNzZWQgaW4gZXZlcnkgc2FtcGxlIChhcyB3ZSBoYXZlIHNlZW4gYmVmb3JlKS4KCgojIFBsb3RzCgojIyBQQ0EKCiMjIyBQQ0Egbm8gc3RhbmRhcmRpemF0aW9uCgpGaXJzdCB3ZSB1c2UgYSBsb2cgdHJhbnNmb3JtYXRpb24gdG8gbWFrZSB0aGUgZGF0YSBhcHByb3hpbWF0aXZlbHkgZm9sbG93IHRoZSBob21vc2NlZGFzdGljaXR5IGFzc3VtcHRpb24uIApgYGB7ciBQQ0F9CiNMb2cgdHJhbnNmb3JtCmxvZ19ub3JtYWxpemVkX2RhdGEgPC0gbG9nKGRhdGFOWikKbG9nX25vcm1hbGl6ZWRfZGF0YVtsb2dfbm9ybWFsaXplZF9kYXRhID09ICItSW5mIl0gPC0gMAoKZGF0YV9wY2EgPC0gcHJjb21wKHQobG9nX25vcm1hbGl6ZWRfZGF0YSkpCmcgPC0gZ2diaXBsb3QoZGF0YV9wY2EsIAogICAgICAgICAgICAgIHNjYWxlID0gMSwgCiAgICAgICAgICAgICAgb2JzLnNjYWxlID0gMSwgCiAgICAgICAgICAgICAgdmFybmFtZS5hYmJyZXYgPSBGQUxTRSwKICAgICAgICAgICAgICB2YXIuYXhlcyA9IEZBTFNFLAogICAgICAgICAgICAgIHBjLmJpcGxvdCA9VFJVRSwKICAgICAgICAgICAgICBjaXJjbGUgPSBUUlVFLCAKICAgICAgICAgICAgICBncm91cHMgPSBkYXRhX2RheSwgCiAgICAgICAgICAgICAgZWxsaXBzZT0gVFJVRSkgKwogIGdndGl0bGUoIlBDQSB3aXRob3V0IHN0YW5kYXJkaXppbmciKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSxwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgCgpnIAoKI3dpbGwgbm90IGJlIG5lZWRlZDogZG9uJ3Qga2VlcCBiaWcgZGF0YQojcmVtb3ZlKGcpCnJlbW92ZShkYXRhX3BjYSkKcmVtb3ZlKGxvZ19ub3JtYWxpemVkX2RhdGEpCmBgYApOb3RlOiBUaGUgUENBIGdyYXBoIGlzIGludGVyZXN0aW5nIGFzIGl0IHNob3dzIHRoYXQgYWZ0ZXIgZWFjaCBkYXkgdGhlIGNsdXN0ZXJzIHNlZW0gdG8gZ28gZG93biBpbiBQQzIgYW5kIGV4dGVuZCB0aGVpciB2YXJpYW5jZSBpbiBQQzEuCgojIyMgUENBIHN0YW5kYXJkaXplZAoKS25vd2luZyB0aGUgaW1wb3J0YW5jZSBvZiBoYXZpbmcgc3RhbmRhcmRpemVkIGRhdGEgZm9yIFBDQSwgd2UgY291bGQgdGhpbmsgb2Ygc3RhbmRhcmRpbmcgb3Vycy4gVGhpcyBpbiBnZW5lcmFsIGlzIGEgZ29vZCBpZGVhLCBhcyB2ZXJhaWJsZXMgYXJlIG9mdGVuIG5vdCBvbiB0aGUgc2FtZSBzY2FsZSBhbmQgdGh1cyBjYW5ub3QgYmUgY29tcGFyZWQgZGlyZWN0bHkuIEhlcmUsIG9uIHJldmFuY2hlIHdlIGhhdmUgZGltZW5zaW9ucyB0aGF0IGFyZSBjb21wYXJhYmxlIGFzIHRoZXkgZWFjaCByZXByZXNlbnQgdGhlIG51bWJlciBvZiBtaVJOQSBpbiBlYWNoIGNlbGwuIEl0IGlzIHRoZXJlZm9yZSBhIGdvb2QgaWRlYSBub3QgdG8gc3RhbmRyZGl6ZSwgYXMgaXQgd2lsbCB1bm5lY2Vzc2FyaWx5IGRlY3JlYXNlIHRoZSB2YXJpYW5jZSBleHBsYWluZWQuIE1vcmUgaW5mb3JtYXRpb24gb24gdGhpcyBjYW4gYmUgZm91bmQgb24gdGhlIGZvbGxvd2luZyBmb3J1bXM6IChoZXJlKVtodHRwOi8vc3RhdHMuc3RhY2tleGNoYW5nZS5jb20vcXVlc3Rpb25zLzEwNTU5Mi9ub3Qtbm9ybWFsaXppbmctZGF0YS1iZWZvcmUtcGNhLWdpdmVzLWJldHRlci1leHBsYWluZWQtdmFyaWFuY2UtcmF0aW9dIG9yIChoZXJlKVtodHRwOi8vc3RhdHMuc3RhY2tleGNoYW5nZS5jb20vcXVlc3Rpb25zLzY5MTU3L3doeS1kby13ZS1uZWVkLXRvLW5vcm1hbGl6ZS1kYXRhLWJlZm9yZS1hbmFseXNpc10uIE91dCBvZiBjdXJpb3NpdHkgd2Ugd2lsbCBzdGlsbCBwbG90IHRoZSBzdGFuZGFyZGl6ZWQgZGF0YToKCmBgYHtyIFBDQV9OWn0KI0xvZyB0cmFuc2Zvcm0KbG9nX25vcm1hbGl6ZWRfZGF0YU5aIDwtIGxvZyhkYXRhTlopCmxvZ19ub3JtYWxpemVkX2RhdGFOWltsb2dfbm9ybWFsaXplZF9kYXRhTlogPT0gIi1JbmYiXSA8LSAwCgpkYXRhX3BjYU5aIDwtIHByY29tcCh0KGxvZ19ub3JtYWxpemVkX2RhdGFOWiksIGNlbnRlciA9IFRSVUUsIHNjYWxlLiA9IFRSVUUpCmcgPC0gZ2diaXBsb3QoZGF0YV9wY2FOWiwgCiAgICAgICAgICAgICAgc2NhbGUgPSAxLCAKICAgICAgICAgICAgICBvYnMuc2NhbGUgPSAxLCAKICAgICAgICAgICAgICB2YXJuYW1lLmFiYnJldiA9IEZBTFNFLAogICAgICAgICAgICAgIHZhci5heGVzID0gRkFMU0UsCiAgICAgICAgICAgICAgcGMuYmlwbG90ID1UUlVFLAogICAgICAgICAgICAgIGNpcmNsZSA9IFRSVUUsIAogICAgICAgICAgICAgIGdyb3VwcyA9IGRhdGFfZGF5LCAKICAgICAgICAgICAgICBlbGxpcHNlPSBUUlVFKSArCiAgZ2d0aXRsZSgiUENBIG5vbiB6ZXJvIGdlbmVzIikgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCkscGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpIAoKZyAKCiN3aWxsIG5vdCBiZSBuZWVkZWQ6IGRvbid0IGtlZXAgYmlnIGRhdGEKI3JlbW92ZShnKQpyZW1vdmUoZGF0YV9wY2FOWikKcmVtb3ZlKGxvZ19ub3JtYWxpemVkX2RhdGFOWikKYGBgCgpGcm9tIHRoaXMgcGxvdCB3ZSBzZWUgdGhhdCBhcyB3ZSd2ZSBzdXBwb3NlZCwgdGhlIHZhcmlhbmNlIGV4cGxhaW5lZCBpcyBsb3dlciB0aGFuIGluIHRoZSBmaXJzdCBvbmUuIFdlIHRodXMgY29uY2x1ZGUgdGhhdCB3ZSBzaG91bGQgc3RpY2sgd2l0aCB0aGUgZmlyc3QgcGxvdCBhcyB3ZSBjYW4gKGJlY2F1c2Ugb24gdGhlIHNhbWUgc2NhbGUpLgoKIyMjIFBDQSB0b3AgNTAgCgpMZXQncyBub3cgcGxvdCB0aGUgdG9wIDUwIGdlbmVzCgpgYGB7ciBQQ0FfdG9wNTB9CiNhcnJhbmdpbmcgZGF0YSBiYXNlZCBvbiB0b3RhbCBleHByZXNzaW9uCmluZGV4VG9wRmlmdHkgPC0gc29ydChyb3dTdW1zKG5fZGF0YSksIGluZGV4PVQsIGRlY3JlYXNpbmc9VFJVRSkkaXhbMTo1MF0KdG9wRmlmdHkgPC0gbl9kYXRhW2luZGV4VG9wRmlmdHksXQojIG5vdGU6IHNtYWxsIGRpZmZlcmVuY2Ugd2l0aCBrZW5ueSBwcm9iYWJseSBjb21lIGZyb20gdGhlIGZhY3QgdGhhdCBoZSBkaWQgbG9nIGJlZm9yZSBhbmQgdGhlbiB0b29rIHRvcCBmaWZ0eSAKCiNMb2cgdHJhbnNmb3JtCmxvZ190b3BGaWZ0eSA8LSBsb2codG9wRmlmdHkpCmxvZ190b3BGaWZ0eVtsb2dfdG9wRmlmdHkgPT0gIi1JbmYiXSA8LSAwCgojUENBCmRhdGFfdG9wRmlmdHkgPC0gcHJjb21wKHQobG9nX3RvcEZpZnR5KSkKZyA8LSBnZ2JpcGxvdChkYXRhX3RvcEZpZnR5LCAKICAgICAgICAgICAgICBzY2FsZSA9IDEsIAogICAgICAgICAgICAgIG9icy5zY2FsZSA9IDEsIAogICAgICAgICAgICAgIHZhcm5hbWUuYWJicmV2ID0gRkFMU0UsCiAgICAgICAgICAgICAgdmFyLmF4ZXMgPSBGQUxTRSwKICAgICAgICAgICAgICBwYy5iaXBsb3QgPVRSVUUsCiAgICAgICAgICAgICAgY2lyY2xlID0gVFJVRSwgCiAgICAgICAgICAgICAgZ3JvdXBzID0gZGF0YV9kYXksIAogICAgICAgICAgICAgIGVsbGlwc2U9IFRSVUUpICsKICBnZ3RpdGxlKCJQQ0EgdG9wIDUwIGdlbmVzIikgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCkscGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpIAoKZwoKI3dpbGwgbm90IGJlIG5lZWRlZDogZG9uJ3Qga2VlcCBiaWcgZGF0YQojcmVtb3ZlKGcpCnJlbW92ZShkYXRhX3RvcEZpZnR5KQpyZW1vdmUobG9nX3RvcEZpZnR5KQpyZW1vdmUodG9wRmlmdHkpCmBgYAoKIyMgQ29ycmVsYXRpb24gaGVhdG1hcApgYGB7ciBjb3JyZWxhdGlvbl9oZWF0bWFwfQojIE5vdGU6IGJvdGggcGxvdHMgb2YgZGF0YU5aIGFuZCBmdWxsIGRhdGEgZ2l2ZXMgc2FtZSBjb3JyZWxhdGlvbiBoZWF0bWFwCm5vcm1hbGl6ZWRfZGF0YV9jb3IgPC0gY29yKGRhdGFOWikgICNjYWxjdWxhdGluZyBzYW1wbGUtc2FtcGxlIGNvcnJlbGF0aW9ucwpzY2FsZWRfbm9ybWFsaXplZF9kYXRhX2NvciA8LSBzY2FsZShub3JtYWxpemVkX2RhdGFfY29yKSAgI3NjYWxpbmcgZm9yIGJldHRlciBjb250cmFzdAoKbGltaXQgPC0gMgpzY2FsZWRfbm9ybWFsaXplZF9kYXRhX2Nvclt3aGljaChzY2FsZWRfbm9ybWFsaXplZF9kYXRhX2NvciA+IGxpbWl0KV0gPC0gbGltaXQgICAgI3RyaW1taW5nIGZvciBiZXR0ZXIgY29udHJhc3QKc2NhbGVkX25vcm1hbGl6ZWRfZGF0YV9jb3Jbd2hpY2goc2NhbGVkX25vcm1hbGl6ZWRfZGF0YV9jb3IgPCAtbGltaXQpXSA8LSAtbGltaXQKCm15cGFsIDwtIHJldihjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoMTEsIlJkQnUiKSkoMTAwKSkgI3NldHRpbmcgY29sb3VyIHBhbGV0dGUKYWxwaGFiZXQgPC0gYygiI2IyZGY4YSIsIiMzM2EwMmMiLCIjZmY3ZjAwIiwiI2ZkYmY2ZiIsIiNiMTU5MjgiLCIjMWY3OGI0IiwiIzZhM2Q5YSIsIiNlMzFhMWMiLCIjYTZjZWUzIiwiI2NhYjJkNiIsIiNmZmZmOTkiLCIjZmI5YTk5IikKcG9wcyA8LSBhbHBoYWJldFthcy5mYWN0b3IoZGF0YV9kYXkpXSAjc2V0dGluZyBwb3B1bGF0aW9uIGNvbG91ciBwYWxldHRlCgpoZWF0bWFwLjIoc2NhbGVkX25vcm1hbGl6ZWRfZGF0YV9jb3IsIFJvd3YgPSBOQSwgQ29sdiA9IE5BLCBzeW1tID0gVCwgI21ha2luZyBhIGhlYXRtYXAKICAgICAgICAgIHRyYWNlID0gIm5vbmUiLCBkZW5kcm9ncmFtID0gIm5vbmUiLCBjb2wgPSBteXBhbCwKICAgICAgICAgIGxhYkNvbCA9IE5BLCBsYWJSb3cgPSBOQSwKICAgICAgICAgIGNleENvbCA9IDAuNDUsIGNleFJvdyA9IDAuNDUsIG1haW4gPSAiU2FtcGxlLVNhbXBsZSBDb3JyZWxhdGlvbnMiLAogICAgICAgICAgQ29sU2lkZUNvbG9ycyA9IHBvcHMpIAoKI3dpbGwgbm90IGJlIG5lZWRlZDogZG9uJ3Qga2VlcCBiaWcgZGF0YQpyZW1vdmUobm9ybWFsaXplZF9kYXRhX2NvcikKcmVtb3ZlKHNjYWxlZF9ub3JtYWxpemVkX2RhdGFfY29yKQojcmVtb3ZlKGhlYXRtYXBQbG90KQpgYGAKCkluIHRoaXMgaGVhdCBtYXAgd2UgY2xlYXJseSBzZWUgdGhlIGhpZ2ggY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgc2FtcGxlcyBvZiBkYXkgMCBhbmQgMSBhbmQgYmV0d2VlbiB0aGUgc2FtcGxlcyBvZiBkYXkgMyBhbmQgNy4KCgojIyB0LVNORSBwbG90cwoKIyMjIEdlbmVyYWwgdC1TTkUKCkxldCdzIHBsb3QgdGhlIHQtU05FIHBsb3RzIG9mIHRoZSBjZWxscyB0aGF0IGFyZW4ndCBkZWFkIHRvIHNlZSBpZiB3ZSBjYW4gZmluZCBjbHVzdGVycyBhbmQgLyBvciBvdXRsaWVycy4gTm90ZSB0aGF0IHdlIGFyZW4ndCB0YWtpbmcgaW50byBhY2NvdW50IGdlbmVzIHRoYXQgYXJlbid0IGV4cHJlc3NlZCBpbiBhbnkgc2FtcGxlcy4KYGBge3IgdHNuZV9HZW5lcmFsfQojIHQtU05FIHBsb3Qgd2l0aCBhbGl2ZSBjZWxscyBhbmQgbm9uIHplcm8gZ2VuZXMKI29yZGVyaW5nIGRhdGEgYnkgZXhwbgphbGl2ZV90c25lX2RhdGEgPC0gY2JpbmQoZGF0YU5aLCAiYXZnX2V4cG4iID0gcm93TWVhbnMoZGF0YU5aKSwgIm1pUk5BIiA9IHJvdy5uYW1lcyhkYXRhTlopKSAKYWxpdmVfdHNuZV9kYXRhIDwtIGRwbHlyOjphcnJhbmdlKGFsaXZlX3RzbmVfZGF0YSxkZXNjKGF2Z19leHBuKSkKYWxpdmVfdHNuZV9kYXRhIDwtIHQoYWxpdmVfdHNuZV9kYXRhKQpjb2xuYW1lcyhhbGl2ZV90c25lX2RhdGEpIDwtIGFsaXZlX3RzbmVfZGF0YVsibWlSTkEiLCBdCiNyZW1vdmVzIHJvd3MgdGhhdCB3ZXJlIGFkZGVkIGZvciBvcmRlcmluZwphbGl2ZV90c25lX2RhdGEgPC0gYWxpdmVfdHNuZV9kYXRhWyFyb3duYW1lcyhhbGl2ZV90c25lX2RhdGEpICVpbiUgYygibWlSTkEiLCJhdmdfZXhwbiIpLCBdCgp0c25lX291dCA8LSBSdHNuZShkaXN0KGFsaXZlX3RzbmVfZGF0YSkpICMgUnVuIFRTTkUKIyBTaG93IHRoZSBvYmplY3RzIGluIHRoZSAyRCB0c25lIHJlcHJlc2VudGF0aW9uCnRTTkVUb3RhbCA8LSBxcGxvdCh4PXRzbmVfb3V0JFlbLDFdLCB5PXRzbmVfb3V0JFlbLDJdLGNvbG9yPWRhdGFfZGF5KSArIAogIGxhYnMoY29sb3VyID0gIkNlbGwgVHlwZSIsIHggPSAidHNuZTEiLCB5ID0gInRzbmUyIikrCiAgZ2d0aXRsZSgidC1TTkUgYWxpdmUgY2VsbHMgYW5kIG5vbiB6ZXJvIGdlbmVzIikgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCkscGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpIAoKdFNORVRvdGFsCgojd2lsbCBub3QgYmUgbmVlZGVkOiBkb24ndCBrZWVwIGJpZyBkYXRhCnJlbW92ZSh0c25lX291dCkKI3JlbW92ZSh0U05FVG90YWwpCmBgYAoKQXMgd2l0aCB0aGUgY29ycmVsYXRpb24gaGVhdG1hcCwgd2Ugc2VlIHRoYXQgIHRoZSBzYW1wbGVzIGZyb20gZGF5IDAgYW5kIDEgYXJlIGNsdXN0ZXJlZCB0b2dldGhlciB3aGlsZSB0aG9zZSBmcm9tIGRheSAzIGFuZCA3IGFyZSBjbHVzdGVyZWQgdG9nZXRoZXIuCgojIyMgdC1TTkUgb2YgRGF5IDAgYW5kIERheSAxCgpOb3cgdGhhdCB3ZSBoYXZlIHNlZW4gdGhhdCB0aGUgc2FtcGxlcyBmcm9tIGRheSAwIGFuZCAxIGFyZSBjbG9zZWx5IHJlbGF0ZWQuIExldCdzIHRyeSB0byB0YWtlIG9ubHkgdGhvc2UgMiBpbiBvcmRlciB0byBzZWUgaWYgd2UgY2FuIHNlcGFyYXRlIHRoZW0gZnJvbSBlYWNoIG90aGVyLiAKCmBgYHtyIHRzbmVfZGF5MDF9CiN0c25lIG9uIERheSAwL0RheSAxIGNlbGxzIG9ubHkKaW5kZXhEYXkwMSA8LSB3aGljaChkYXRhX2RheSAlaW4lIGMoIkRheSAwIiwiRGF5IDEiKSkKZ3JvdXBfb25lX2RhdGEgPC0gYWxpdmVfdHNuZV9kYXRhW2luZGV4RGF5MDEsIF0gI3NlbGVjdGluZyBvbmx5IGRheSAwIGFuZCBkYXkgMSBjZWxscwp0c25lX291dCA8LSBSdHNuZShkaXN0KGdyb3VwX29uZV9kYXRhKSkgIyBSdW4gVFNORQojIFNob3cgdGhlIG9iamVjdHMgaW4gdGhlIDJEIHRzbmUgcmVwcmVzZW50YXRpb24KdHNuZURheTAxIDwtIHFwbG90KHg9dHNuZV9vdXQkWVssMV0sIHk9dHNuZV9vdXQkWVssMl0sY29sb3I9ZGF0YV9kYXlbaW5kZXhEYXkwMV0pICsKICBsYWJzKGNvbG91ciA9ICJDZWxsIFR5cGUiLCB4ID0gInRzbmUxIiwgeSA9ICJ0c25lMiIpICsKICBnZ3RpdGxlKCJ0LVNORSBvbmx5IGRheSAwIGFuZCAxIikgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCkscGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpIAoKdHNuZURheTAxCgojd2lsbCBub3QgYmUgbmVlZGVkOiBkb24ndCBrZWVwIGJpZyBkYXRhCnJlbW92ZSh0c25lX291dCkKI3JlbW92ZSh0c25lRGF5MDEpCmBgYAoKVGhlIHQtU05FIGNhbiBjbGVhcmx5IG5vdCBzZXBhcmF0ZSB0aGUgMiBzYW1wbGVzIGZyb20gZWFjaCBvdGhlci4gRmluYWxseSBsZXQncyBpbnZlc3RpZ2F0ZSB3aGV0aGVyIHRoZXkgY2FuIGJlIHNlcGFyYXRlZCB3aXRoIGEgdC1TTkUgaW4gMyBkaW1lbnNpb246CgpgYGB7ciB0c25lX2RheTAxXzNEfQp0c25lX291dCA8LSBSdHNuZShkaXN0KGdyb3VwX29uZV9kYXRhKSwgZGltcyA9IDMpICMgUnVuIFRTTkUgaW4gMyBkaW1lbnNpb25zCgpwbG90X2x5KHg9dHNuZV9vdXQkWVssMV0sCiAgICAgICAgeT10c25lX291dCRZWywyXSwKICAgICAgICB6PXRzbmVfb3V0JFlbLDNdLAogICAgICAgIHR5cGU9InNjYXR0ZXIzZCIsCiAgICAgICAgY29sb3I9ZGF0YV9kYXlbaW5kZXhEYXkwMV0sCiAgICAgICAgbW9kZT0ibWFya2VycyIpICU+JSAKICBsYXlvdXQodGl0bGUgPSAndC1TTkUgZGF5IDAgYW5kIDEgM0QnKQoKI3dpbGwgbm90IGJlIG5lZWRlZDogZG9uJ3Qga2VlcCBiaWcgZGF0YQpyZW1vdmUodHNuZV9vdXQpCnJlbW92ZShncm91cF9vbmVfZGF0YSkKI3JlbW92ZSh0c25lRGF5MDEpCmBgYAoKV2UgY2FuIHN0aWxsIG5vdCBkaXN0aW5ndWlzaCBib3RoIHR5cGUgb2YgY2VsbHMuIFRoaXMgcmVhbGx5IHNob3dzIGhvdyBzaW1pbGFyIHRoZXkgYXJlLgoKIyMjIHQtU05FIG9mIERheSAwIGFuZCBEYXkgMQoKTm93IGxldCdzIGxvb2sgYXQgdGhlIGNsdXN0ZXIgRGF5IDMgYW5kIDcsIHRvIHNlZSBpZiB0aGV5IGNhbiBiZSBkaXN0aW5ndWlzaGVkLgoKYGBge3IgdHNuZV9kYXkzN30KI3RzbmUgb24gRGF5IDAvRGF5IDEgY2VsbHMgb25seQppbmRleERheTM3IDwtIHdoaWNoKGRhdGFfZGF5ICVpbiUgYygiRGF5IDMiLCJEYXkgNyIpKQpncm91cF90d29fZGF0YSA8LSBhbGl2ZV90c25lX2RhdGFbaW5kZXhEYXkzNywgXSAjc2VsZWN0aW5nIG9ubHkgZGF5IDAgYW5kIGRheSAxIGNlbGxzCnRzbmVfb3V0IDwtIFJ0c25lKGRpc3QoZ3JvdXBfdHdvX2RhdGEpKSAjIFJ1biBUU05FCiMgU2hvdyB0aGUgb2JqZWN0cyBpbiB0aGUgMkQgdHNuZSByZXByZXNlbnRhdGlvbgp0c25lRGF5MzcgPC0gcXBsb3QoeD10c25lX291dCRZWywxXSwgeT10c25lX291dCRZWywyXSxjb2xvcj1kYXRhX2RheVtpbmRleERheTM3XSkgKwogIGxhYnMoY29sb3VyID0gIkNlbGwgVHlwZSIsIHggPSAidHNuZTEiLCB5ID0gInRzbmUyIikgKwogIGdndGl0bGUoInQtU05FIG9ubHkgZGF5IDMgYW5kIDciKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSxwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgCgp0c25lRGF5MzcKCiN3aWxsIG5vdCBiZSBuZWVkZWQ6IGRvbid0IGtlZXAgYmlnIGRhdGEKcmVtb3ZlKHRzbmVfb3V0KQpyZW1vdmUoYWxpdmVfdHNuZV9kYXRhKQojcmVtb3ZlKHRzbmVEYXkzNykKYGBgCgpBcyBiZWZvcmUsIHRoZSAyIHR5cGUgb2YgY2VsbHMgY2Fubm90IGJlIGRpc3Rpbmd1aXNoZWQgd2l0aCBhIHQtU05FIHBsb3QgaW4gMkQuIFRoZXkgd2lsbCBwcm9iYWJseSBub3QgYmUgZGlzdGluZ3Vpc2hhYmxlIGluIDNEIGJ1dCBsZXQncyBiZSBzdXJlOgoKYGBge3IgdHNuZV9kYXkzN18zRH0KdHNuZV9vdXQgPC0gUnRzbmUoZGlzdChncm91cF90d29fZGF0YSksIGRpbXMgPSAzKSAjIFJ1biBUU05FIGluIDMgZGltZW5zaW9ucwoKcGxvdF9seSh4PXRzbmVfb3V0JFlbLDFdLAogICAgICAgIHk9dHNuZV9vdXQkWVssMl0sCiAgICAgICAgej10c25lX291dCRZWywzXSwKICAgICAgICB0eXBlPSJzY2F0dGVyM2QiLAogICAgICAgIGNvbG9yPWRhdGFfZGF5W2luZGV4RGF5MzddLAogICAgICAgIG1vZGU9Im1hcmtlcnMiKSAlPiUgCiAgbGF5b3V0KHRpdGxlID0gJ3QtU05FIGRheSAzIGFuZCA3IDNEJykKCiN3aWxsIG5vdCBiZSBuZWVkZWQ6IGRvbid0IGtlZXAgYmlnIGRhdGEKcmVtb3ZlKHRzbmVfb3V0KQpyZW1vdmUoZ3JvdXBfdHdvX2RhdGEpCmBgYAoKTm90IHN1cHJpc2luZ2x5LCB0aGUgc2Vjb25kIGNsdXN0ZXIgY2Fubm90IGJlIHNlcHJhdGVkIGZ1cnRoZXIgd2l0aCAzIGRpbWVuc2lvbmFsIHQtU05FLgoKCiMgRml0IGxpbmVhciBtb2RlbAoKTm90ZSB0aGF0IGZvciBmaXR0aW5nIGxpbmVhciBtb2RlbHMsIHdlIGNhbm5vdCB1c2UgdGhlIERBVEFTRVEgbGlicmFyeSBhcyBpdCByZXF1aXJlcyBjb3VudHMgKGkuZS4gZGlzY3JldGUgdmFsdWVzKS4gV2Ugbm93IGhhdmUgY29udGludW91cyB2YWx1ZXMgYmVjYXVzZSBvZiB0aGV5IHdheSB3ZSBub3JtYWxpemVkIHRoZSBkYXRhLgoKIyMgVm9vbQoKIyMjIE1lYW4tVmFyaWFuY2UgdHJlbmQKCiMjIyMgSW5pdGlhbCBNZWFuLVZhcmlhbmNlIHRyZW4KCkZpcnN0IGxldCB1cyB2aXN1YWxpemUgdGhlIG1lYW4tdmFyaWFuY2UgdHJlbmQsIHRvIHNlZS4gCgpgYGB7ciBpbnRpYWxfbWVhbl92YXJpYW5jZX0KI3dvcmtpbmcgLi4uIEhPVyBUTyBVU0UgREFUQURFU0VRIE9OIE5PUk1BTElaRUQgPT4gTk9UIENPVU5UUyBBTlkgTU9SRT8/ICsgSVMgSVQgV09SVEggSVQgPyBjQU4gd2Ugcm91bmQgPwojZGF0YURFU2VxIDwtIHJsb2coYXMubWF0cml4KGRhdGEpLCBibGluZD1GQUxTRSApCgpkZ2UgPC0gREdFTGlzdChjb3VudHM9ZGF0YU5aLCBncm91cCA9IGRhdGFfZGF5KQojIGFwcGxpZXMgVE1NIG5vcm1hbGl6YXRpb24gdG8gZGdlCgpkZ2UgPC0gY2FsY05vcm1GYWN0b3JzKGRnZSkKZGF0YV92b29tZWQgPC0gdm9vbShkZ2UsZGVzaWduLHBsb3Q9VFJVRSkKCiN3aWxsIG5vdCBiZSBuZWVkZWQ6IGRvbid0IGtlZXAgYmlnIGRhdGEKcmVtb3ZlKGRnZSkKYGBgCgpUaGUgbWVhbi12YXJpYW5jZSB0cmVuZCBpcyBzdXByaXNpbmc6IGl0IGRvZXNuJ3QgbG9vayBmbGF0IGVub3VnaC4gVGhlIGZpcnN0IGh5cG9ydGhlc2lzIHdlIGhhZCBpcyB0aGF0IHdlIHRoZXJlIHdhcyBhIHByb2JsZW0gYmVjYXVzZSB3ZSBub3JtYWxpemUgYnkgc2FtcGxlcyBhbmQgdGhlbiBsaW1tYSBkb2VzIGl0IGFnYWluLiBCdXQgbm90IG5vcm1haWxpemluZyBvdXIgZGF0YSBkb2Vzbid0IGNoYW5nZSB0aGUgY3VydmUgb2YgdGhlIHBsb3QuIFdlIHRoZW4gdGhvdWdodCB0aGF0IG1heWJlIGxpbW1hIHdhcyBkb2luZyBzb21ldGhpbmcgdGhhdCByZXF1aXJlZCBkaXNjcmV0ZSBkYXRhIChhcyBpdCBpcyBtYWRlIGZvciBjb3VudCBkYXRhKSwgb3VyIGRhdGEgaXNuJ3QgZGlzY3JldGUgYXMgd2Ugbm9ybWFpbGl6ZWQgaXQgYmFzZWQgb24gc3Bpa2UgUk5BLiBCdXQgcm91bmRpbmcgdGhlIGRhdGEgZG9lc24ndCBjaGFuZ2UgYW55dGhpbmcgZWl0aGVyLiBXZSB3aWxsIGhhdmUgdG8gbG9vayBkZWVwZXIgYXQgdGhlIG1lYW5pbmcgb2YgdGUgY3VydmUgb2YgdGhlIHBsb3QgYW5kIHdoZXRoZXIgb3VyIGRhdGEgZG9lc24ndCBmb2xsb3cgdGhlIFZvb20gYXNzdW1wdGlvbnMuIE5vdGUgdGhhdCB0aGUgZGF0YSBtYXkgYWxzbyBiZSBzdHJhbmdlIGR1ZSB0byB0aGUgbmF0dXJlIG9mIG1pUk5BIGRhdGEsIGluZGVlZCBpbiBSTkFzZXEgd2Ugb2Z0ZW4gaGF2ZSBoaWdoIHZhbHVlIG9mIGNvdW50cyBidXQgaW4gbWlSTkEgdGhlIG51bWJlciBvZiBjb3VudHMgYXJlIG11Y2ggbG93ZXIuIFRoaXMgY291bGQgY2F1c2UgdGhlIHNwaWtlIHdlIHNlZSBiZWxvdyB4ID0gemVybyAoaS5lLiB2ZXJ5IGxvdyBtZWFuKS4KCkxldHMgY2hlY2sgd2hldGhlciB0aGUgc3RyYW5nZSBtZWFuIHZhcmlhbmNlIGlzIGR1ZSB0byB0aGUgY2x1c3RlcnMgdGhhdCB3ZSBoYWQuCgpgYGB7ciBoaXN0b2dyYW1tX3Zvb219CmRmIDwtIGRhdGFfdm9vbWVkJEUKZGF0YWY8LSBtdXRhdGUoZGF0YS5mcmFtZSh0KGRmKSksIGdyb3VwID0gZGF0YV9kYXkpICU+JSAKICBnYXRoZXIobWlybmEsIGV4cCwgLSBncm91cCkgCgpnZ3Bsb3QoZGF0YWYsIGFlcyh4PWV4cCkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKGNvbG9yID0gZ3JvdXApKSArCiAgZ2d0aXRsZSgiSW5pdGlhbCBpc3RvZ3JhbSBvZiBjb3VudHMiKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSxwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgCgojd2lsbCBub3QgYmUgbmVlZGVkOiBkb24ndCBrZWVwIGJpZyBkYXRhCnJlbW92ZShkYXRhZikKcmVtb3ZlKGRmKQpgYGAKCldlIHNlZSB0aGF0IG91ciBtb2RlbCBzZWVtcyB0byBiZSBiaW1vZGFsIGJ1dCB0aGF0IHRoZSBiaW1vZGFsaXR5IGRvZXNuJ3Qgc2VlbSB0byBiZSBkdWUgdG8gdGhlIGNsdXN0ZXJzLgoKIyMjIyBGaW5hbCBNZWFuLVZhcmlhbmNlCldlIHJlYWxpemVkIHRoYXQgaXMgaW1wb3J0YW50IHRoYXQgd2UgdXNlIG9ubHkgdGhlIGdlbmVzIHdpdGggbm8gbm9uIHplcm8gdmFsdWVzIGZvciBldmVyeSBzYW1wbGUgYXMgd2UgY2FuIHNlZSBpbiBwYXJhZ3JhcGggMTUuMyBvZiAobGltbWEgbWFudWFsKVtodHRwczovL3d3dy5iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL2RldmVsL2Jpb2MvdmlnbmV0dGVzL2xpbW1hL2luc3QvZG9jL3VzZXJzZ3VpZGUucGRmXS4gRnJvbSB0aGUgc2FtZSBhcnRpY2xlIHRoZXkgc2F5IHRoYXQgYXMgYSBydWxlIG9mIHRodW1iIGlzIHRvIHJldGFpbiByb3dzIHRoYXQgaGF2ZSBhdCBsZWFzdCAxMCBjb3VudHMgZm9yIGEgd29ydGh3aGlsZSBudW1iZXIgb2Ygc2FtcGxlcy4gCgpgYGB7ciBmaW5hbF9tZWFuX3ZhcmlhbmNlfQpkYXRhTlpGaWx0ZXJkIDwtZGF0YU5aW3Jvd1N1bXMoZGF0YU5aPj0xMCk+PXJvdW5kKDAuMypuY29sKGRhdGFOWikpLF0KCmRnZSA8LSBER0VMaXN0KGNvdW50cz1kYXRhTlpGaWx0ZXJkLCBncm91cCA9IGRhdGFfZGF5KQojIGFwcGxpZXMgVE1NIG5vcm1hbGl6YXRpb24gdG8gZGdlCgojZGdlIDwtIGRnZVtpc0V4cHIsXQpkZ2UgPC0gY2FsY05vcm1GYWN0b3JzKGRnZSkKZGF0YV92b29tZWQgPC0gdm9vbShkZ2UsZGVzaWduLHBsb3Q9VFJVRSkKCiN3aWxsIG5vdCBiZSBuZWVkZWQ6IGRvbid0IGtlZXAgYmlnIGRhdGEKcmVtb3ZlKGRnZSkKcmVtb3ZlKGRhdGFOWkZpbHRlcmQpCmBgYAoKSXQgaXMgbm93IGFscmVhZHkgYSBiaXQgYmV0dGVyLiBXZSBhbHNvIHNlZSB0aGF0IHRoZSBtZWFuIHZhcmlhbmNlIHRyZW5kIHNlYW0gdG8gYmUgZGVjcmVhc2luZyB2ZXJ5IHF1aWNrbHkgYW5kIHN0ZWFkaWx5LCB3ZSBjYW4gdGh1cyBjb25jbHVkZSB0aGF0IHRoZSBleHBlcmltZW50IHNlZW0gdG8gYmUgb2YgbG93IGJpb2xvZ2ljYWwgdmFyaWF0aW9uLiBGb3IgbW9yZSBpbmZvcm1hdGlvbiBwbGVhc2Ugc2VlIHRoZSAiUmVtb3ZpbmcgaGV0ZXJvc2NlZGFzY2l0eSBmcm9tIGNvdW50IGRhdGEiIHN1YnBhcnQgb2YgKHRoaXMgcGFwZXIpW2h0dHBzOi8vZjEwMDByZXNlYXJjaC5jb20vYXJ0aWNsZXMvNS0xNDA4XQoKSGVyZSBpcyBhbiBleGFtcGxlIG9mIHRoZSBkYXRhIHdlIGhhdmU6CgpgYGB7ciB9CmRhdGFfdm9vbWVkWzE6MiwxOjEwXQpgYGAKCiMjIyMgRmluYWwgbWVhbi12YXJpYW5jZSBiaXMKClRoaW5raW5nIGFib3V0IGl0LCB3ZSBzaG91bGRuJ3QgZmlsdGVyIG9uIGhhdmluZyBhcyBnb29kIHBlcmNlbnRhZ2Ugb2YgdGhlIHNhbXBsZXMgdGhhdCBhcmUgbm9uIHplcm8gYnV0IHJhdGhlciBoYXZpbmcgYSBtYWpvcml0eSBvZiBub24gemVybyBpbiBhdCBsZWFzdCBvbmUgZ3JvdXAgd2UgaGF2ZS4gSW5kZWVkIHRoYXQncyB3aGF0IHJlYWxseSBpbnRlcmVzdHMgdXMgYXQgdGhlIGVuZCwgYmVjYXVzZSB3ZSBhcmUgZ29pbmcgdG8gY29tcGFyZSB0aGUgZ3JvdXBzIQoKYGBge3IgZmluYWxfbWVhbl92YXJpYW5jZV9iaXN9CmluZGV4RGF5MCA8LSB3aGljaChkYXRhX2RheSA9PSAiRGF5IDAiKQppbmRleERheTEgPC0gd2hpY2goZGF0YV9kYXkgPT0gIkRheSAxIikKaW5kZXhEYXkzIDwtIHdoaWNoKGRhdGFfZGF5ID09ICJEYXkgMyIpCmluZGV4RGF5NyA8LSB3aGljaChkYXRhX2RheSA9PSAiRGF5IDciKQoKZGF0YU5aRmlsdGVyZEJpcyA8LSBkYXRhTlpbcm93U3VtcyhkYXRhTlpbLGluZGV4RGF5MF0+PTEwKT49cm91bmQoMC41MCpsZW5ndGgoaW5kZXhEYXkwKSkgfAogICAgICAgICAgICAgICAgICAgICAgICAgIHJvd1N1bXMoZGF0YU5aWyxpbmRleERheTFdPj0xMCk+PXJvdW5kKDAuNTAqbGVuZ3RoKGluZGV4RGF5MSkpIHwKICAgICAgICAgICAgICAgICAgICAgICAgICByb3dTdW1zKGRhdGFOWlssaW5kZXhEYXkzXT49MTApPj1yb3VuZCgwLjUwKmxlbmd0aChpbmRleERheTMpKSB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgcm93U3VtcyhkYXRhTlpbLGluZGV4RGF5N10+PTEwKT49cm91bmQoMC41MCpsZW5ndGgoaW5kZXhEYXk3KSkgLF0KCmRnZSA8LSBER0VMaXN0KGNvdW50cz1kYXRhTlpGaWx0ZXJkQmlzLCBncm91cCA9IGRhdGFfZGF5KQojIGFwcGxpZXMgVE1NIG5vcm1hbGl6YXRpb24gdG8gZGdlCmRnZSA8LSBjYWxjTm9ybUZhY3RvcnMoZGdlKQpkYXRhX3Zvb21lZCA8LSB2b29tKGRnZSxkZXNpZ24scGxvdD1UUlVFKQoKI3dpbGwgbm90IGJlIG5lZWRlZDogZG9uJ3Qga2VlcCBiaWcgZGF0YQpyZW1vdmUoZGdlKQpgYGAKCldlIHNlZSB0aGF0IGl0IGlzIHZlcnkgY2xvc2UgdG8gYmVmb3JlIGJ1dCBhdCBsZWFzdCBub3cgdGhlcmUncyBubyBzdWJqZWN0aXZpdHkgb2YgImEgd29ydGhpbGUgbnVtYmVyIG9mIHNhbXBsZXMgbmVlZCB0byBoYXZlIG1vcmUgdGhhbiAxMCBjb3VudHMgZm9yIHRoYXQgbWlSTkEiLgoKTGV0cyBsb29rIG5vdyBhdCB0aGUgaGlzdG9ncmFtIHRvIHNlZSBob3cgaXQgY2hhbmdlZCBpdDoKCmBgYHtyIEZpbmFsX2hpc3RvZ3JhbW1fdm9vbX0KZGYgPC0gZGF0YV92b29tZWQkRQpkYXRhZjwtIG11dGF0ZShkYXRhLmZyYW1lKHQoZGYpKSwgZ3JvdXAgPSBkYXRhX2RheSkgJT4lIAogIGdhdGhlcihtaXJuYSwgZXhwLCAtIGdyb3VwKSAKCmdncGxvdChkYXRhZiwgYWVzKHg9ZXhwKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShhZXMoY29sb3IgPSBncm91cCkpICsKICBnZ3RpdGxlKCJGaW5hbCBoaXN0b2dyYW0gb2YgY291bnRzIikgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCkscGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpIAoKI3dpbGwgbm90IGJlIG5lZWRlZDogZG9uJ3Qga2VlcCBiaWcgZGF0YQpyZW1vdmUoZGF0YWYpCnJlbW92ZShkZikKYGBgCgoqKldoeSBzdHJhbmdlIHNoYXBlPyoqOgpJIGp1c3QgcmVhbGl6ZWQgdGhlIHJlYXNvbiBvZiB0aGUgc3RyYW5nZSBzaGFwZTogZXZlcnl0aGluZyBpcyBkdWUgdG8gdGhlIGV4dHJlbWUgdmFyaWFuY2UgYXQgbG93IGNvdW50ICEgSW5kZWVkIGdlbmVyYWxseSB0aGUgbWVhbiB2YXJpYW5jZSBwbG90IHNob3dzIGEgJFxzcXJ0KFNEKSQgdGhhdCBpcyBhcm91bmQgMSwgYnV0IG91cnMgaXMgYXJvdW5kIDIsIGJ1dCBvbmx5IGF0IGEgbG93IGNvdW50LiBUaGUgcmVhc29uIGlzIHNpbXBsZTogdGhlIGNsdXN0ZXJzISBXZSBjYW4gbm93IGV4cGxhaW4gYWxsIHRoZSBjdXJ2ZTogaW4gdGhlIHVuZmlsdGVyZWQgbWVhbi12YXJpYW5jZSBwbG90IHRoZXJlIHdhcyBhIHN0cmFuZ2UgYXNjZW50IGF0IHRoZSBiaWdpbmluZywgdGhpcyBpcyBkdWUgdG8gdGhlIGZhY3QgdGhhdCBtaVJOQSBoYXZlIGEgcmVsYXRpdmVseSBsb3cgbnVtYmVyIG9mIGNvdW50cyBhbmQgaXMgZWl0aGVyIG9uIG9yIG9mZiBzbyB3ZSBoYWQgYSBsb3Qgb2YgemVyb3MsIHRoZXNlIGFyZSBub3cgZmlsdGVyZWQgb3V0LiBUaGVuIHRoZXJlIGlzIGEgdmVyeSBiaWcgdmFyaWFuY2UgYXQgbG93IHRvIGF2ZXJhZ2UgbnVtYmVyIG9mIGNvdW50cywgdGhpcyBpcyBkdWUgdG8gdGhlIGZhY3QgdGhhdCB0aGUgY2x1c3RlcnMgYXJlIHZlcnkgc3Ryb25nIGluIG91ciBzYW1wbGVzLCB0aGUgbWlSTkEgYXJlIGVpdGhlciBvbiBvciBvZmYgZGVwZW5kaW5nIG9uIHRoZSBjbHVzdGVycyAoY2x1c3RlciAxOiBkYXkgMCBhbmQgMSwgY2x1c3RlciAyOiBkYXkgMyBhbmQgNykgc28gd2hlbiBsb29raW5nIGF0IHBvc3NpYmx5IGludGVyZXN0aW5nIG1pUk5BIHRoZXkgYXJlIG9mdGVuIG9uIGluIG9uZSBvZiB0aGUgY2x1c3RlciBhbmQgb2ZmIGluIHRoZSBvdGhlciB0aGlzIHRodXMgcmVzdWx0cyBpbiBhIHJlbGF0aXZlbHkgbG93IG51bWJlciBvZiBjb3VudHMgYnV0IGEgdmVyeSBiaWcgdmFyaWFuY2UgKGJpbW9kYWwgZGF0YSkuIEZvdyBoaWdoIGNvdW50cyB3ZSBzZWUgdGhhdCB0aGUgdmFyaWFuY2UgaXMgcmVhbGx5IGxvdywgdGhpcyBpcyBzaW1wbHkgc2hvd2luZyAibm90IGludGVyZXN0aW5nIiBtaVJOQSB0aGF0IGFyZSBhbHdheXMgdmVyeSBoaWdoIGFuZCB0aHVzIGhhdmUgYSBsb3cgdmFyaWFuY2UhCgpPbmUgZ29vZCB3YXkgdG8gZ28gYXJvdW5kIHRoYXQgaXMgdG8gbG9vayBkaWZmZXJlbnRseSBhdCB0aGUgZ2VuZXMgdGhhdCBhcmUgYWx3YXlzIGhpZ2ggYW5kIHRob3NlIHRoYXQgYXJlIG9ubHkgaGlnaCBpbiBvbmUgb2YgdGhlIGNsdXN0ZXJzICh3aGVuIHRoZXkgYXJlIGxvdyBpbiBib3RoIHRoZXkgd2VyZSBhbHJlYWR5IGZpbHRlcmVkIG91dCkuIExldHMgbG9vayBhdCB0aGUgcGxvdHMgdG8gc2VlIGlmIHRoaXMgaHlwb3RoZXNpcyBpcyB0cnVlCgojIyMjIyBBbHdheXMgaGlnaCBtaXJSTkEKCmBgYHtyIG1lYW5fdmFyaWFuY2VfYWx3YXlzSGlnaH0Kcm93c0Fsd2F5c0hpZ2ggPC0gcm93U3VtcyhkYXRhTlpGaWx0ZXJkQmlzPj0xMi41KT49cm91bmQoMC44MCpuY29sKGRhdGFOWkZpbHRlcmRCaXMpKQpkYXRhTlpGaWx0ZXJBbHdheXNIaWdoIDwtIGRhdGFOWkZpbHRlcmRCaXNbcm93c0Fsd2F5c0hpZ2gsXQoKZGdlIDwtIERHRUxpc3QoY291bnRzPWRhdGFOWkZpbHRlckFsd2F5c0hpZ2gsIGdyb3VwID0gZGF0YV9kYXkpCiMgYXBwbGllcyBUTU0gbm9ybWFsaXphdGlvbiB0byBkZ2UKCiNkZ2UgPC0gZGdlW2lzRXhwcixdCmRnZSA8LSBjYWxjTm9ybUZhY3RvcnMoZGdlKQpkYXRhX3Zvb21lZEFIIDwtIHZvb20oZGdlLGRlc2lnbixwbG90PVRSVUUpCgojd2lsbCBub3QgYmUgbmVlZGVkOiBkb24ndCBrZWVwIGJpZyBkYXRhCnJlbW92ZShkZ2UpCmBgYAoKSWYgdGhlIGh5cG90aGVzaXMgaXMgdHJ1ZSB0aGVuIHRoZSBoaXN0b2dyYW0gc2hvdWxkIGJlIG5vdyBub3JtYWxseSBkaXN0cmlidXRlZCAobm8gbW9yZSBiaW5vbWlhbCBiZWNhdXNlIHRoZSBnZW5lcyB3ZSBhcmUgbG9va2luZyBhdCBhcmUgYWx3YXlzIGhpZ2hseSBleHByZXNzZWQpCgpgYGB7ciBoaXN0b2dyYW1tX3Zvb21fYWx3YXlzSGlnaH0KZGYgPC0gZGF0YV92b29tZWRBSCRFCmRhdGFmPC0gbXV0YXRlKGRhdGEuZnJhbWUodChkZikpLCBncm91cCA9IGRhdGFfZGF5KSAlPiUgCiAgZ2F0aGVyKG1pcm5hLCBleHAsIC0gZ3JvdXApIAoKZ2dwbG90KGRhdGFmLCBhZXMoeD1leHApKSArIAogIGdlb21faGlzdG9ncmFtKGFlcyhjb2xvciA9IGdyb3VwKSkgKwogIGdndGl0bGUoIkluaXRpYWwgaXN0b2dyYW0gb2YgY291bnRzIikgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCkscGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpIAoKI3dpbGwgbm90IGJlIG5lZWRlZDogZG9uJ3Qga2VlcCBiaWcgZGF0YQpyZW1vdmUoZGF0YWYpCnJlbW92ZShkZikKYGBgCgojIyMjIyBtaVJOQSBoaWdoIGluIGEgc2luZ2xlIGdyb3VwCgpgYGB7ciBtZWFuX3ZhcmlhbmNlX2hpZ2hTaW5nbGVHcm91cH0KZGF0YU5aRmlsdGVySGlnaFNpbmdsZUdyb3VwIDwtIGRhdGFOWkZpbHRlcmRCaXNbIXJvd3NBbHdheXNIaWdoLF0KCmRnZSA8LSBER0VMaXN0KGNvdW50cz1kYXRhTlpGaWx0ZXJIaWdoU2luZ2xlR3JvdXAsIGdyb3VwID0gZGF0YV9kYXkpCiMgYXBwbGllcyBUTU0gbm9ybWFsaXphdGlvbiB0byBkZ2UKCiNkZ2UgPC0gZGdlW2lzRXhwcixdCmRnZSA8LSBjYWxjTm9ybUZhY3RvcnMoZGdlKQpkYXRhX3Zvb21lZEhTRyA8LSB2b29tKGRnZSxkZXNpZ24scGxvdD1UUlVFKQoKI3dpbGwgbm90IGJlIG5lZWRlZDogZG9uJ3Qga2VlcCBiaWcgZGF0YQpyZW1vdmUoZGdlKQpgYGAKCgpOb3cgaGVyZSB0aGVyZSBzaG91bGQgc3RpbGwgYmUgYSBiaW1vZGFsIGRpc3RyaWJ1dGlvbiBhcyB3aGVuIG9uZSBjbHVzdGVyIGlzIGhpZ2ggdGhlIG90aGVyIG9uZSB3aWxsIGJlIGxvdyBhbmQgdmlzIHZlcnNhLgoKYGBge3IgaGlzdG9ncmFtbV92b29tX2hpZ2hTaW5nbGVHcm91cH0KZGYgPC0gZGF0YV92b29tZWRIU0ckRQpkYXRhZjwtIG11dGF0ZShkYXRhLmZyYW1lKHQoZGYpKSwgZ3JvdXAgPSBkYXRhX2RheSkgJT4lIAogIGdhdGhlcihtaXJuYSwgZXhwLCAtIGdyb3VwKSAKCmdncGxvdChkYXRhZiwgYWVzKHg9ZXhwKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShhZXMoY29sb3IgPSBncm91cCkpICsKICBnZ3RpdGxlKCJJbml0aWFsIGlzdG9ncmFtIG9mIGNvdW50cyIpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTQpLHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSAKCiN3aWxsIG5vdCBiZSBuZWVkZWQ6IGRvbid0IGtlZXAgYmlnIGRhdGEKcmVtb3ZlKGRhdGFmKQpyZW1vdmUoZGYpCmBgYAp3ZSBzZWUgdGhhdCBhcyBoeXB0aG9zaXplZCB0aGUgaGlzdG9ncmFtbSBpcyBiaW1vZGFsCgojIyMjIE1lYW4gdmFyaWFuY2UgdHJlbmQgbm8gbG9nCgpOT1RFOiB0aGlzIGlzIG5vdCBpbXBvcnRhbnQgYW55IG1vcmUgIQpOb3RlOiBTZWVpbmcgdGhlIHN0cmFuZ2UgcGxvdCBhYm92ZSBtYWtlcyB1cyB0aGluayB0aGF0IG1heWJlIG91ciBjb3VudCBkYXRhIGRvZXNuJ3QgbmVlZCB0byBiZSBsb2cgdHJhbnNmb3JtZWQuIExldCdzIGludmVzdGlnYXRlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgbWVhbiBhbmQgdGhlIHZhcmlhbmNlIG9mIG91IGRhdGEuCgpgYGB7ciBzcXJ0NF9tZWFuLXZhcmlhbmNlfQojd29ya2luZyAuLi4gSE9XIFRPIFVTRSBEQVRBREVTRVEgT04gTk9STUFMSVpFRCA9PiBOT1QgQ09VTlRTIEFOWSBNT1JFPz8gKyBJUyBJVCBXT1JUSCBJVCA/IGNBTiB3ZSByb3VuZCA/CiNkYXRhREVTZXEgPC0gcmxvZyhhcy5tYXRyaXgoZGF0YSksIGJsaW5kPUZBTFNFICkKCiN0YWtlcyBvbmx5IGdlbmVzIHRoYXQgYXJlIG5vbiB6ZXJvIGluIG1hbnkgc2FtcGxlcwojdCA8LSBuX2RhdGFbd2hpY2gocm93U3VtcyhuX2RhdGEpID4gMzAwKSxdIAoKI3RyaWVzIHBsb3R0aW5nIGRpcmVjdGx5IHdpdGhvdXQgdm9vbQptIDwtIHJvd01lYW5zKGRhdGFOWikKUm93U2lnbWFTcXJ0IDwtIGZ1bmN0aW9uKHgpIHsKICAocm93U3VtcygoeCAtIHJvd01lYW5zKHgpKV4yKS8oZGltKHgpWzJdIC0gMSkpXigxLzQpCn0KdiA8LSBSb3dTaWdtYVNxcnQoZGF0YU5aKQoKcGxvdHh5IDwtIGRhdGEuZnJhbWUobWVhbj1tLHNpZ21hU3FydD12KQpnZ3Bsb3QocGxvdHh5LCBhZXMoeD1tZWFuLCB5PXNpZ21hU3FydCkpICsKICAgIGdlb21fcG9pbnQoc2hhcGU9MSkgKyAgICAjIFVzZSBob2xsb3cgY2lyY2xlcwogICAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtLCAgICMgQWRkIGxpbmVhciByZWdyZXNzaW9uIGxpbmUKICAgICAgICAgICAgICAgIHNlPUZBTFNFKSArICMgRG9uJ3QgYWRkIHNoYWRlZCBjb25maWRlbmNlIHJlZ2lvbgogIHlsaW0oMCwgNzUwMCkgKyAKICB4bGltKDAsNzUwMCkgKyAKICBnZ3RpdGxlKCJNZWFuIHZhcmlhbmNlIHJlbGF0aW9uc2hpcCBub3QgVm9vbSIpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTQpLHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSAKCiN3aWxsIG5vdCBiZSBuZWVkZWQ6IGRvbid0IGtlZXAgYmlnIGRhdGEKcmVtb3ZlKHBsb3R4eSkKYGBgCgpGcm9tIHRoaXMgcGxvdCB3ZSBjbGVhcmx5IHNlZSB0aGF0IG91ciB2YXJpYW5jZSBncm93cyB3aXRoIGZvdXJ0aCBwb3FlciBvZiBvdXIgbWVhbi4gVGhlIHJlYXNvbmluZyBiZWhpbmQgdGhpcyBkaWZmZXJlbnQgcmVsYXRpb25zaGlwIGlzIHN0aWxsIHVuY2xlYXIgdG8gdXMgKD8/Pz8/Pz8/Pz8/Pz8gYmlvbG9naWNhbGx5KSwgYnV0IGl0IGNvdWxkIGluZGljYXRlIHRoYXQgd2Ugc2hvdWxkbid0IHdvcmsgd2l0aCB0aGUgZGVmYXVsdCBsaW1tYSBwYWNrYWdlIGFuZCB0aGF0IHdlIHNob3VsZCBtYXliZSBkbyB0aGUgYW5hbHlzaXMgbWFudWFsbHkgKD8/Pz8/Pz8/KS4gIAoKIyMjIEZpdCBsaW5lYXIgbW9kZWwKCmBgYHtyIHRlc3RfbGluZWFyX21vZGVsIH0KCmZpdCA8LSBsbUZpdChkYXRhX3Zvb21lZCwgZGVzaWduKQpmaXQgPC0gY29udHJhc3RzLmZpdChmaXQsIGNvbnRyYXN0cz1jb250cmFzdE1hdHJpeCkKZWZpdCA8LSBlQmF5ZXMoZml0KQp0b3BUYWJsZShlZml0LCBjb2VmPWNvbG5hbWVzKGNvZWYoZWZpdCkpKQpwbG90U0EoZWZpdCkKCiN3aWxsIG5vdCBiZSBuZWVkZWQ6IGRvbid0IGtlZXAgYmlnIGRhdGEKcmVtb3ZlKGZpdCkKcmVtb3ZlKGRhdGFfdm9vbWVkKQpgYGAKCkhlcmUgdGhlcmUgaXMgYSBwcm9ibGVtIGFzIHdlIGRvIG5vdCBzZWUgdGhlIGZpdHRlZCBsaW5lICg/Pz8/PykuCgoKIyMjIyBFeGFtaW5pbmcgdGhlIG51bWJlciBvZiBERSBnZW5lcwoKTGV0J3Mgbm93IGxvb2sgYXQgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gbGV2ZWxzIG9mIGdlbmVzLiBOb3RlIHRoYXQgdGhlIGFkanVzdGVkIHAtdmFsdWUgY3V0b2ZmIGlzIDUlLgoKYGBge3IgdGVzdF9saW5lYXJfbW9kZWxfc3VtbWFyeSB9CmR0IDwtIGRlY2lkZVRlc3RzKGVmaXQpCnN1bW1hcnkoZHQpCmBgYAoKQXMgd2UgaGF2ZSBhbHJlYWR5IHByZXZpb3VzbHkgc2VlbiBpbiB0aGUgbXVsdGlwbGUgcGxvdHMgb2YgdGhlIHByZXZpb3VzIHNlY3Rpb246IG1vc3QgZGlmZmVyZW50aWFsIGV4cHJlc3NlZCBnZW5lcyBhcmUgYmV0d2VlbiBkYXkgMC8xIGFuZCAzLzcuIFdlIGFsc28gbm90ZSB0aGF0IGEgbG90IG9mIGdlbmVzIGluIERheSAzIGFuZCA3IGFyZSBkb3ducmVndWxhdGVkIChjb21wYXJlZCB0byBkYXkgMCBhbmQgMSkuCgojIyMjIEZpbmRpbmcgZ2VuZXMgdGhhdCBhcmUgb2Z0ZW4gZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGNvbXBhcmVkIHRvIGRheSAwCgpMZXQncyBsb29rIGF0IHRoZSBnZW5lcyB0aGF0IGFyZSBhbHdheXMgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGNvbXBhcmVkIHRvIGRheSAwIAoKYGBge3IgY29tbW9uX0RFX2dlbmVzX2RheTAgfQojIEZpbmRpbmcgZ2VuZXMgdGhhdCBhcmUgbm90IHplcm8gaW4gZXZlcnkgY29tcGFyYWlzb24gd2l0aCBkYXkgMApjb21tb25ERWdlbmVzRGF5MCA8LSB3aGljaChkdFssMV0hPTAgJiBkdFssMl0hPTAgJiBkdFssM10hPTApCm5hbWVzKGNvbW1vbkRFZ2VuZXNEYXkwKQpgYGAKCkxldCdzIHZpc3VhbGlzZSBpdCB3aXRoIGEgbmljZSB2ZW5uIGRpYWdyYW1tCgpgYGB7ciBkYXkwX0RFX3Zlbm4gfQp2ZW5uRGlhZ3JhbShkdFssMTozXSwgY2lyY2xlLmNvbD1jKCJ0dXJxdW9pc2UiLCAic2FsbW9uIiwgImdyZWVuIikpCmBgYAoKIyMjIyBGaW5kaW5nIGdlbmVzIHRoYXQgYXJlIG9mdGVuIGRpZmZlcmVudGlhbGx5IGJldHdlZW4gZGF5IDAvMSBhbmQgZGF5IDMvNwoKTGV0J3MgbG9vayBhdCB0aGUgZ2VuZXMgdGhhdCBhcmUgYWx3YXlzIGRpZmZlcmVudGlhbGx5IGJldHdlZW4gZGF5IDAvMSBhbmQgMy83IGFzIHRoZXkgc2VlbSB0byBiZSB0aGUgb25lcyBvZiBpbnRlcmVzdC4KCmBgYHtyIGNvbW1vbl9ERV9nZW5lc19kYXkwMS0zNyB9CiMgRmluZGluZyBnZW5lcyB0aGF0IGFyZSBub3QgemVybyBpbiBldmVyeSBjb21wYXJhaXNvbiB3aXRoIGRheSAwCmNvbW1vbkRFZ2VuZXNEYXkwMTM3IDwtIHdoaWNoKGR0WywyXSE9MCAmIGR0WywzXSE9MCAmIGR0Wyw0XSE9MCAmIGR0Wyw1XSE9MCkKbmFtZXMoY29tbW9uREVnZW5lc0RheTAxMzcpCmBgYAoKTGV0J3MgdmlzdWFsaXNlIGl0IHdpdGggYSBuaWNlIHZlbm4gZGlhZ3JhbW0KCmBgYHtyIGRheTAxMzdfREVfdmVubiB9CnZlbm5EaWFncmFtKGR0WywyOjVdLCBjaXJjbGUuY29sPWMoInR1cnF1b2lzZSIsICJzYWxtb24iLCAiZ3JlZW4iLCJ5ZWxsb3ciKSkKYGBgCgojIyMjIEZpbmRpbmcgZ2VuZXMgdGhhdCBhcmUgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGJldHdlZW4gY2x1c3RlcnMgYnV0IG5vdCB3aGl0aGluIGNsdXN0ZXJzCgpGaW5hbGx5IHdoYXQgd2UgYXJlIHJlYWxseSBpbnRlcmVzdGVkIGluIGFyZSBnZW5lcyB0aGF0IGFyZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgYmV0d2VlbiBjbHVzdGVycyBidXQgbm90IHdoaXRoaW4gY2x1c3RlcnM6IGhlcmUgYXJlIHRoZXNlIGdlbmVzOgoKYGBge3IgY29tbW9uX0RFX2dlbmVzX2JldHdlZW5DTHVzdGVyc19ub3RXaGl0aGluIH0KIyBGaW5kaW5nIGdlbmVzIHRoYXQgYXJlIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBiZXR3ZWVuIGNsdXN0ZXJzIGJ1dCBub3Qgd2hpdGhpbiBjbHVzdGVycwpjb21tb25ERWdlbmVzQmV0d2Vlbk5vdFdoaXRoaW4gPC0gd2hpY2goZHRbLDJdIT0wICYgZHRbLDNdIT0wICYgZHRbLDRdIT0wICYgZHRbLDVdIT0wICYgZHRbLDFdPT0wICYgZHRbLDZdPT0wKQpuYW1lcyhjb21tb25ERWdlbmVzQmV0d2Vlbk5vdFdoaXRoaW4pCmBgYA==